diff --git a/.gitignore b/.gitignore index ea3d7b8..9965252 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.xml *.so *.txt +*.orig bin/* !bin/Makefile.am .prepared* diff --git a/Makefile.am b/Makefile.am index a2e3451..b411dde 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,32 +5,31 @@ CWMP_VERSION = 3.0.1 bin_PROGRAMS = icwmpd icwmpd_SOURCES = \ - ./common.c \ - ./log.c \ - ./cwmp_uci.c \ - ./config.c \ - ./session.c \ - ./backupSession.c \ - ./digauth.c \ - ./event.c \ - ./http.c \ - ./netlink.c \ - ./ubus_utils.c \ - ./datamodel_interface.c \ - ./cwmp_cli.c \ - ./notifications.c \ - ./cwmp_zlib.c \ - ./cwmp_du_state.c \ - ./download.c \ - ./upload.c \ - ./sched_inform.c \ - ./xml.c \ - ./rpc_soap.c \ - ./diagnostic.c \ - ./reboot.c \ - ./heartbeat.c \ - ./cwmp.c \ - ./ssl_utils.c + ./src/common.c \ + ./src/log.c \ + ./src/cwmp_uci.c \ + ./src/config.c \ + ./src/session.c \ + ./src/backupSession.c \ + ./src/digauth.c \ + ./src/event.c \ + ./src/http.c \ + ./src/ubus_utils.c \ + ./src/datamodel_interface.c \ + ./src/cwmp_cli.c \ + ./src/notifications.c \ + ./src/cwmp_zlib.c \ + ./src/cwmp_du_state.c \ + ./src/download.c \ + ./src/upload.c \ + ./src/sched_inform.c \ + ./src/xml.c \ + ./src/rpc.c \ + ./src/diagnostic.c \ + ./src/reboot.c \ + ./src/heartbeat.c \ + ./src/cwmp.c \ + ./src/ssl_utils.c icwmpd_CFLAGS = \ $(AM_CFLAGS) \ @@ -66,4 +65,4 @@ icwmpd_LDADD = \ icwmpd_CFLAGS+=-DCWMP_VERSION=\"$(CWMP_VERSION)\" icwmpd_LDFLAGS+=-DCWMP_VERSION=\"$(CWMP_VERSION)\" -icwmpd_CFLAGS+=-I./inc +icwmpd_CFLAGS+=-I.. diff --git a/configure.ac b/configure.ac index e6a636f..30bd834 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_INIT([icwmp], [1.0], [dev@iopsys.eu]) AM_INIT_AUTOMAKE -AC_CONFIG_SRCDIR([cwmp.c]) +AC_CONFIG_SRCDIR([src/cwmp.c]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) diff --git a/gitlab-ci/functional-test.sh b/gitlab-ci/functional-test.sh index 84bd75e..a541391 100755 --- a/gitlab-ci/functional-test.sh +++ b/gitlab-ci/functional-test.sh @@ -8,6 +8,21 @@ pwd trap cleanup EXIT trap cleanup SIGINT +function check_valgrind_xml() { + echo "Checking memory leaks..." + grep -q "UninitCondition" memory-report.xml + error_on_zero $? + + grep -q "Leak_PossiblyLost" memory-report.xml + error_on_zero $? + + grep -q "Leak_DefinitelyLost" memory-report.xml + error_on_zero $? + + grep -q "Leak_StillReachable" memory-report.xml + error_on_zero $? +} + date +%s > timestamp.log echo "Compiling icmwp" build_icwmp @@ -59,6 +74,11 @@ done echo "Stop all services" supervisorctl stop icwmpd +check_valgrind_xml + +cp test/files/etc/config/users /etc/config/ +cp test/files/etc/config/wireless /etc/config/ + echo "Verify Custom notifications" echo "#### Start custom_notifications ####" >> "$icwmp_master_log" if ./test/script/verify_custom_notifications.sh; then diff --git a/gitlab-ci/shared.sh b/gitlab-ci/shared.sh index ad05f20..3b8b8c1 100644 --- a/gitlab-ci/shared.sh +++ b/gitlab-ci/shared.sh @@ -38,6 +38,7 @@ function exec_cmd() function configure_genieacs() { + start_acs sleep 10 echo "create a new user" curl -X POST 'http://localhost:3000/init' -H "Content-Type: application/json" --data '{"users": true, "presets": true, "filters": true, "device": true, "index": true, "overview": true}' >/dev/null 2>&1 diff --git a/inc/cwmp_zlib.h b/inc/cwmp_zlib.h deleted file mode 100644 index acafa16..0000000 --- a/inc/cwmp_zlib.h +++ /dev/null @@ -1,17 +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 - * - */ - -#ifndef __ZLIB_H -#define __ZLIB_H - -int zlib_compress(char *message, unsigned char **zmsg, int *zlen, int type); - -#endif diff --git a/inc/diagnostic.h b/inc/diagnostic.h deleted file mode 100644 index fe2e1e9..0000000 --- a/inc/diagnostic.h +++ /dev/null @@ -1,25 +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) 2019 iopsys Software Solutions AB - * Author: Imen Bhiri - * Author: Amin Ben Ramdhane - */ - -#ifndef __DIAGNOSTIC__H -#define __DIAGNOSTIC__H - -bool set_diagnostic_parameter_structure_value(char *parameter_name, char *value); - -int cwmp_download_diagnostics(); -int cwmp_upload_diagnostics(); -int cwmp_ip_ping_diagnostics(); -int cwmp_nslookup_diagnostics(); -int cwmp_traceroute_diagnostics(); -int cwmp_udp_echo_diagnostics(); -int cwmp_serverselection_diagnostics(); - -#endif diff --git a/inc/http.h b/inc/http.h deleted file mode 100644 index 049367f..0000000 --- a/inc/http.h +++ /dev/null @@ -1,34 +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) 2011 Luka Perkov - */ - -#ifndef _FREECWMP_HTTP_H__ -#define _FREECWMP_HTTP_H__ - -#include "common.h" - -extern char *fc_cookies; - -#define HTTP_TIMEOUT 60 - -struct http_client { - struct curl_slist *header_list; - char *url; -}; - -void http_set_timeout(void); - -int http_client_init(struct cwmp *cwmp); -void http_client_exit(void); -int http_send_message(struct cwmp *cwmp, char *msg_out, int msg_out_len, char **msg_in); - -void http_server_init(void); -void http_server_listen(void); -void http_success_cr(void); - -#endif diff --git a/inc/netlink.h b/inc/netlink.h deleted file mode 100755 index 1aaddaf..0000000 --- a/inc/netlink.h +++ /dev/null @@ -1,19 +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-2019 iopsys Software Solutions AB - * Author Mohamed Kallel - * Author Anis Ellouze - * - */ - -#ifndef _NETLINK_H__ -#define _NETLINK_H__ - -int netlink_init(void); -int netlink_init_v6(void); - -#endif diff --git a/inc/reboot.h b/inc/reboot.h deleted file mode 100644 index 276eacf..0000000 --- a/inc/reboot.h +++ /dev/null @@ -1,19 +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) 2021 iopsys Software Solutions AB - * Author Amin Ben Ramdhane - */ - -#ifndef _REBOOT_H__ -#define _REBOOT_H__ - -#include "common.h" - -void launch_reboot_methods(struct cwmp *cwmp); - -#endif //_REBOOT_H__ - diff --git a/inc/xml.h b/inc/xml.h deleted file mode 100644 index d3d0e69..0000000 --- a/inc/xml.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __XML__H_ -#define __XML__H_ - -#include -#include "session.h" -#include "common.h" - -#define CWMP_MXML_TAB_SPACE " " -#define MAX_SCHEDULE_INFORM_QUEUE 10 - -#define MXML_DELETE(X) \ - do { \ - if (X) { \ - mxmlDelete(X); \ - X = NULL; \ - } \ - } while (0) - -extern const char *cwmp_urls[]; -int xml_prepare_msg_out(struct session *session); -int xml_prepare_lwnotification_message(char **msg_out); -int xml_set_cwmp_id_rpc_cpe(struct session *session); -int xml_recreate_namespace(mxml_node_t *tree); -const char *whitespace_cb(mxml_node_t *node, int where); -int xml_set_cwmp_id(struct session *session); -int xml_send_message(struct cwmp *cwmp, struct session *session, struct rpc *rpc); -mxml_node_t *mxmlFindElementOpaque(mxml_node_t *node, mxml_node_t *top, const char *text, int descend); -char *xml__get_attribute_name_by_value(mxml_node_t *node, const char *value); -char *xml_get_cwmp_version(int version); -void xml_exit(void); -void load_response_xml_schema(mxml_node_t **schema); -void load_notification_xml_schema(mxml_node_t **tree); - -#endif diff --git a/netlink.c b/netlink.c deleted file mode 100644 index d7dfb5c..0000000 --- a/netlink.c +++ /dev/null @@ -1,282 +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 - * Copyright (C) 2011-2012 Luka Perkov - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "netlink.h" -#include "cwmp_uci.h" -#include "log.h" -#include "event.h" - -static int itfcmp(char *itf1, char *itf2); -static void netlink_new_msg(struct uloop_fd *ufd, unsigned events); -static struct uloop_fd netlink_event = {.cb = netlink_new_msg }; -static struct uloop_fd netlink_event_v6 = {.cb = netlink_new_msg }; - -static int itfcmp(char *itf1, char *itf2) -{ - int index = 0; - int status = 1; - char *str = NULL; - char *buf1 = NULL; - char *buf2 = NULL; - - if (itf1 == NULL || itf2 == NULL) - return status; - - if (itf1[0] == '\0') - goto end; - str = strchr(itf1, '.'); - if (str == NULL) - goto end; - index = (int)(str - itf1); - if (!index) - goto end; - - buf1 = malloc(index); - if (!buf1) - goto end; - - strncpy(buf1, itf1, index); - buf1[index] = '\0'; - if (itf2[0] == '\0') - goto end; - - str = strchr(itf2, '.'); - if (str == NULL) - goto end; - - index = (int)(str - itf2); - if (!index) - goto end; - - buf2 = malloc(index); - if (!buf2) - goto end; - - strncpy(buf2, itf1, index); - buf2[index] = '\0'; - - if (strcmp(buf1, buf2) == 0) - status = 0; -end: - if (buf1) - free(buf1); - if (buf2) - free(buf2); - return status; -} - -static void freecwmp_netlink_interface(struct nlmsghdr *nlh) -{ - struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(nlh); - struct rtattr *rth = IFA_RTA(ifa); - int rtl = IFA_PAYLOAD(nlh); - char if_name[IFNAMSIZ], if_addr[INET_ADDRSTRLEN]; - - memset(&if_name, 0, sizeof(if_name)); - memset(&if_addr, 0, sizeof(if_addr)); - - if (ifa->ifa_family == AF_INET) { //CASE IPv4 - while (rtl && RTA_OK(rth, rtl)) { - if (rth->rta_type != IFA_LOCAL) { - rth = RTA_NEXT(rth, rtl); - continue; - } - - uint32_t addr = htonl(*(uint32_t *)RTA_DATA(rth)); - if (htonl(13) == 13) { - // running on big endian system - } else { - // running on little endian system - addr = __builtin_bswap32(addr); - } - - if_indextoname(ifa->ifa_index, if_name); - if (itfcmp(cwmp_main.conf.interface, if_name)) { - rth = RTA_NEXT(rth, rtl); - continue; - } - - inet_ntop(AF_INET, &(addr), if_addr, INET_ADDRSTRLEN); - - FREE(cwmp_main.conf.ip); - cwmp_main.conf.ip = strdup(if_addr); - cwmp_uci_set_varstate_value("cwmp", "cpe", "ip", cwmp_main.conf.ip); - cwmp_commit_package("cwmp", UCI_VARSTATE_CONFIG); - connection_request_ip_value_change(&cwmp_main, IPv4); - break; - } - } else { //CASE IPv6 - while (rtl && RTA_OK(rth, rtl)) { - char pradd_v6[128]; - if (rth->rta_type != IFA_ADDRESS || ifa->ifa_scope == RT_SCOPE_LINK) { - rth = RTA_NEXT(rth, rtl); - continue; - } - inet_ntop(AF_INET6, RTA_DATA(rth), pradd_v6, sizeof(pradd_v6)); - if_indextoname(ifa->ifa_index, if_name); - if (strncmp(cwmp_main.conf.interface, if_name, IFNAMSIZ)) { - rth = RTA_NEXT(rth, rtl); - continue; - } - - FREE(cwmp_main.conf.ipv6); - cwmp_main.conf.ipv6 = strdup(pradd_v6); - cwmp_uci_set_varstate_value("cwmp", "cpe", "ipv6", cwmp_main.conf.ip); - cwmp_commit_package("cwmp", UCI_VARSTATE_CONFIG); - connection_request_ip_value_change(&cwmp_main, IPv6); - break; - } - } -} - -static void netlink_new_msg(struct uloop_fd *ufd, unsigned events __attribute__((unused))) -{ - struct nlmsghdr *nlh; - char buffer[BUFSIZ]; - size_t msg_size; - - memset(&buffer, 0, sizeof(buffer)); - - nlh = (struct nlmsghdr *)buffer; - if ((int)(msg_size = recv(ufd->fd, nlh, BUFSIZ, 0)) == -1) { - CWMP_LOG(ERROR, "error receiving netlink message"); - return; - } - - while ((size_t)msg_size > sizeof(*nlh)) { - int len = nlh->nlmsg_len; - int req_len = len - sizeof(*nlh); - - if (req_len < 0 || (size_t)len > msg_size) { - CWMP_LOG(ERROR, "error reading netlink message"); - return; - } - - if (!NLMSG_OK(nlh, msg_size)) { - CWMP_LOG(ERROR, "netlink message is not NLMSG_OK"); - return; - } - - if (nlh->nlmsg_type == RTM_NEWADDR) - freecwmp_netlink_interface(nlh); - - msg_size -= NLMSG_ALIGN(len); - nlh = (struct nlmsghdr *)((char *)nlh + NLMSG_ALIGN(len)); - } -} - -int netlink_init_v6(void) -{ - struct { - struct nlmsghdr hdr; - struct ifaddrmsg msg; - } req; - struct sockaddr_nl addr; - int sock[2]; - - memset(&addr, 0, sizeof(addr)); - memset(&req, 0, sizeof(req)); - - if ((sock[0] = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { - CWMP_LOG(ERROR, "couldn't open NETLINK_ROUTE socket"); - return -1; - } - - addr.nl_family = AF_NETLINK; - addr.nl_groups = RTMGRP_IPV6_IFADDR; - if ((bind(sock[0], (struct sockaddr *)&addr, sizeof(addr))) == -1) { - CWMP_LOG(ERROR, "couldn't bind netlink socket"); - return -1; - } - - netlink_event_v6.fd = sock[0]; - uloop_fd_add(&netlink_event_v6, ULOOP_READ | ULOOP_EDGE_TRIGGER); - - if ((sock[1] = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) == -1) { - CWMP_LOG(ERROR, "couldn't open NETLINK_ROUTE socket"); - return -1; - } - - req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; - req.hdr.nlmsg_type = RTM_GETADDR; - req.msg.ifa_family = AF_INET6; - - if ((send(sock[1], &req, req.hdr.nlmsg_len, 0)) == -1) { - CWMP_LOG(ERROR, "couldn't send netlink socket"); - return -1; - } - - struct uloop_fd dummy_event = {.fd = sock[1] }; - netlink_new_msg(&dummy_event, 0); - - return 0; -} - -int netlink_init(void) -{ - struct { - struct nlmsghdr hdr; - struct ifaddrmsg msg; - } req; - struct sockaddr_nl addr; - int sock[2]; - - memset(&addr, 0, sizeof(addr)); - memset(&req, 0, sizeof(req)); - - if ((sock[0] = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { - CWMP_LOG(ERROR, "couldn't open NETLINK_ROUTE socket"); - return -1; - } - - addr.nl_family = AF_NETLINK; - addr.nl_groups = RTMGRP_IPV4_IFADDR; - if ((bind(sock[0], (struct sockaddr *)&addr, sizeof(addr))) == -1) { - CWMP_LOG(ERROR, "couldn't bind netlink socket"); - return -1; - } - - netlink_event.fd = sock[0]; - uloop_fd_add(&netlink_event, ULOOP_READ | ULOOP_EDGE_TRIGGER); - - if ((sock[1] = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) == -1) { - CWMP_LOG(ERROR, "couldn't open NETLINK_ROUTE socket"); - return -1; - } - - req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; - req.hdr.nlmsg_type = RTM_GETADDR; - req.msg.ifa_family = AF_INET; - - if ((send(sock[1], &req, req.hdr.nlmsg_len, 0)) == -1) { - CWMP_LOG(ERROR, "couldn't send netlink socket"); - return -1; - } - - struct uloop_fd dummy_event = {.fd = sock[1] }; - netlink_new_msg(&dummy_event, 0); - - return 0; -} diff --git a/rpc_soap.c b/rpc_soap.c deleted file mode 100755 index d3cfaa2..0000000 --- a/rpc_soap.c +++ /dev/null @@ -1,2852 +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) 2011-2012 Luka Perkov - * Copyright (C) 2012 Jonas Gorski - */ - -#include "rpc_soap.h" -#include "download.h" -#include "cwmp_du_state.h" -#include "log.h" -#include "event.h" -#include "datamodel_interface.h" -#include "event.h" -#include "xml.h" -#include "backupSession.h" -#include "notifications.h" -#include "upload.h" -#include "sched_inform.h" -#include "diagnostic.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 -#define DM_CONN_REQ_URL "Device.ManagementServer.ConnectionRequestURL" - -struct cwmp_namespaces ns; -const struct rpc_cpe_method rpc_cpe_methods[] = { [RPC_CPE_GET_RPC_METHODS] = { "GetRPCMethods", cwmp_handle_rpc_cpe_get_rpc_methods, AMD_1 }, - [RPC_CPE_SET_PARAMETER_VALUES] = { "SetParameterValues", cwmp_handle_rpc_cpe_set_parameter_values, AMD_1 }, - [RPC_CPE_GET_PARAMETER_VALUES] = { "GetParameterValues", cwmp_handle_rpc_cpe_get_parameter_values, AMD_1 }, - [RPC_CPE_GET_PARAMETER_NAMES] = { "GetParameterNames", cwmp_handle_rpc_cpe_get_parameter_names, AMD_1 }, - [RPC_CPE_SET_PARAMETER_ATTRIBUTES] = { "SetParameterAttributes", cwmp_handle_rpc_cpe_set_parameter_attributes, AMD_1 }, - [RPC_CPE_GET_PARAMETER_ATTRIBUTES] = { "GetParameterAttributes", cwmp_handle_rpc_cpe_get_parameter_attributes, AMD_1 }, - [RPC_CPE_ADD_OBJECT] = { "AddObject", cwmp_handle_rpc_cpe_add_object, AMD_1 }, - [RPC_CPE_DELETE_OBJECT] = { "DeleteObject", cwmp_handle_rpc_cpe_delete_object, AMD_1 }, - [RPC_CPE_REBOOT] = { "Reboot", cwmp_handle_rpc_cpe_reboot, AMD_1 }, - [RPC_CPE_DOWNLOAD] = { "Download", cwmp_handle_rpc_cpe_download, AMD_1 }, - [RPC_CPE_UPLOAD] = { "Upload", cwmp_handle_rpc_cpe_upload, AMD_1 }, - [RPC_CPE_FACTORY_RESET] = { "FactoryReset", cwmp_handle_rpc_cpe_factory_reset, AMD_1 }, - [RPC_CPE_CANCEL_TRANSFER] = { "CancelTransfer", cwmp_handle_rpc_cpe_cancel_transfer, AMD_3 }, - [RPC_CPE_SCHEDULE_INFORM] = { "ScheduleInform", cwmp_handle_rpc_cpe_schedule_inform, AMD_1 }, - [RPC_CPE_SCHEDULE_DOWNLOAD] = { "ScheduleDownload", cwmp_handle_rpc_cpe_schedule_download, AMD_3 }, - [RPC_CPE_CHANGE_DU_STATE] = { "ChangeDUState", cwmp_handle_rpc_cpe_change_du_state, AMD_3 }, - [RPC_CPE_X_FACTORY_RESET_SOFT] = { "X_FactoryResetSoft", cwmp_handle_rpc_cpe_x_factory_reset_soft, AMD_1 }, - [RPC_CPE_FAULT] = { "Fault", cwmp_handle_rpc_cpe_fault, AMD_1 } }; - -struct rpc_acs_method rpc_acs_methods[] = { [RPC_ACS_INFORM] = { "Inform", cwmp_rpc_acs_prepare_message_inform, cwmp_rpc_acs_parse_response_inform, cwmp_rpc_acs_destroy_data_inform, 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 } -}; - -char *custom_forced_inform_parameters[MAX_NBRE_CUSTOM_INFORM] = { 0 }; -char *boot_inform_parameters[MAX_NBRE_CUSTOM_INFORM] = { 0 }; -int nbre_custom_inform = 0; -int nbre_boot_inform = 0; -char *forced_inform_parameters[] = { - "Device.RootDataModelVersion", - "Device.DeviceInfo.HardwareVersion", - "Device.DeviceInfo.SoftwareVersion", - "Device.DeviceInfo.ProvisioningCode", - "Device.ManagementServer.ParameterKey", - DM_CONN_REQ_URL, - "Device.ManagementServer.AliasBasedAddressing" -}; - -int xml_handle_message(struct session *session) -{ - struct rpc *rpc_cpe; - char *c; - int i; - mxml_node_t *b; - struct cwmp *cwmp = &cwmp_main; - struct config *conf; - conf = &(cwmp->conf); - - /* get method */ - if (icwmp_asprintf(&c, "%s:%s", ns.soap_env, "Body") == -1) { - CWMP_LOG(INFO, "Internal error"); - session->fault_code = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - b = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); - - if (!b) { - CWMP_LOG(INFO, "Invalid received message"); - session->fault_code = FAULT_CPE_REQUEST_DENIED; - goto fault; - } - session->body_in = b; - - while (1) { - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND_FIRST); - if (!b) - goto error; - if (mxmlGetType(b) == MXML_ELEMENT) - break; - } - - c = (char *)mxmlGetElement(b); - /* convert QName to localPart, check that ns is the expected one */ - if (strchr(c, ':')) { - char *tmp = strchr(c, ':'); - size_t ns_len = tmp - c; - - if (strlen(ns.cwmp) != ns_len) { - CWMP_LOG(INFO, "Invalid received message"); - session->fault_code = FAULT_CPE_REQUEST_DENIED; - goto fault; - } - - if (strncmp(ns.cwmp, c, ns_len)) { - CWMP_LOG(INFO, "Invalid received message"); - session->fault_code = FAULT_CPE_REQUEST_DENIED; - goto fault; - } - - c = tmp + 1; - } else { - CWMP_LOG(INFO, "Invalid received message"); - session->fault_code = FAULT_CPE_REQUEST_DENIED; - goto fault; - } - CWMP_LOG(INFO, "SOAP RPC message: %s", c); - rpc_cpe = NULL; - for (i = 1; i < __RPC_CPE_MAX; i++) { - if (i != RPC_CPE_FAULT && strcmp(c, rpc_cpe_methods[i].name) == 0 && rpc_cpe_methods[i].amd <= conf->supported_amd_version) { - CWMP_LOG(INFO, "%s RPC is supported", c); - rpc_cpe = cwmp_add_session_rpc_cpe(session, i); - if (rpc_cpe == NULL) - goto error; - break; - } - } - if (!rpc_cpe) { - CWMP_LOG(INFO, "%s RPC is not supported", c); - session->fault_code = FAULT_CPE_METHOD_NOT_SUPPORTED; - goto fault; - } - return 0; -fault: - rpc_cpe = cwmp_add_session_rpc_cpe(session, RPC_CPE_FAULT); - if (rpc_cpe == NULL) - goto error; - return 0; -error: - return -1; -} - -/* - * [RPC ACS]: Inform - */ - -static int xml_prepare_events_inform(mxml_node_t *b1, struct session *session) -{ - mxml_node_t *node, *b2; - char c[128]; - unsigned int n = 0; - struct list_head *ilist; - struct event_container *event_container; - struct cwmp *cwmp = &cwmp_main; - - if (!b1) - return -1; - - list_for_each (ilist, &(session->head_event_container)) { - event_container = list_entry(ilist, struct event_container, list); - node = mxmlNewElement(b1, "EventStruct"); - if (!node) - goto error; - b2 = mxmlNewElement(node, "EventCode"); - if (!b2) - goto error; - if (event_container->code == EVENT_IDX_0BOOTSTRAP || event_container->code == EVENT_IDX_1BOOT) - cwmp->is_boot = true; - b2 = mxmlNewOpaque(b2, EVENT_CONST[event_container->code].CODE); - if (!b2) - goto error; - b2 = mxmlNewElement(node, "CommandKey"); - if (!b2) - goto error; - if (event_container->command_key) { - b2 = mxmlNewOpaque(b2, event_container->command_key); - if (!b2) - goto error; - } - mxmlAdd(b1, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node); - n++; - } - if (n) { - if (snprintf(c, sizeof(c), "cwmp:EventStruct[%u]", n) == -1) - return -1; - mxmlElementSetAttr(b1, "xsi:type", "soap_enc:Array"); - mxmlElementSetAttr(b1, "soap_enc:arrayType", c); - } - return 0; - -error: - return -1; -} - -static int xml_prepare_parameters_inform(struct cwmp_dm_parameter *dm_parameter, mxml_node_t *parameter_list, int *size) -{ - mxml_node_t *node, *b; - b = mxmlFindElementOpaque(parameter_list, parameter_list, dm_parameter->name, MXML_DESCEND); - if (b && dm_parameter->value != NULL) { - node = mxmlGetParent(b); - b = mxmlFindElement(node, node, "Value", NULL, NULL, MXML_DESCEND_FIRST); - if (!b) - return 0; - mxml_node_t *c = mxmlGetFirstChild(b); - if (c && strcmp(dm_parameter->value, mxmlGetOpaque(c)) == 0) - return 0; - mxmlDelete(b); - (*size)--; - - goto create_value; - } else if (dm_parameter->value == NULL) - return 0; - node = mxmlNewElement(parameter_list, "ParameterValueStruct"); - if (!node) - return -1; - - b = mxmlNewElement(node, "Name"); - if (!b) - return -1; - - b = mxmlNewOpaque(b, dm_parameter->name); - if (!b) - return -1; - -create_value: - b = mxmlNewElement(node, "Value"); - if (!b) - return -1; - -#ifdef ACS_MULTI - mxmlElementSetAttr(b, "xsi:type", (dm_parameter->type && dm_parameter->type[0] != '\0') ? dm_parameter->type : "xsd:string"); -#endif - b = mxmlNewOpaque(b, dm_parameter->value); - if (!b) - return -1; - - (*size)++; - return 0; -} - -static void load_inform_xml_schema(mxml_node_t **tree, struct cwmp *cwmp, struct session *session) -{ - char declaration[1024] = {0}; - - if (tree == NULL) - return; - - *tree = NULL; - - snprintf(declaration, sizeof(declaration), "?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?"); - mxml_node_t *xml = mxmlNewElement(NULL, declaration); - if (xml == NULL) - return; - - mxml_node_t *envelope = mxmlNewElement(xml, "soap_env:Envelope"); - if (envelope == NULL) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(envelope, "xmlns:soap_env", "http://schemas.xmlsoap.org/soap/envelope/"); - mxmlElementSetAttr(envelope, "xmlns:soap_enc", "http://schemas.xmlsoap.org/soap/encoding/"); - mxmlElementSetAttr(envelope, "xmlns:xsd", "http://www.w3.org/2001/XMLSchema"); - mxmlElementSetAttr(envelope, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); - mxmlElementSetAttr(envelope, "xmlns:cwmp", cwmp_urls[(cwmp->conf.supported_amd_version) - 1]); - - mxml_node_t *header = mxmlNewElement(envelope, "soap_env:Header"); - if (header == NULL) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *id = mxmlNewElement(header, "cwmp:ID"); - if (id == NULL) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(id, "soap_env:mustUnderstand", "1"); - - mxml_node_t *node = NULL; - if (cwmp->conf.supported_amd_version >= 4) { - node = mxmlNewElement(header, "cwmp:SessionTimeout"); - if (!node) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(node, "soap_env:mustUnderstand", "0"); - node = mxmlNewInteger(node, cwmp->conf.session_timeout); - if (!node) { - MXML_DELETE(xml); - return; - } - } - - if (cwmp->conf.supported_amd_version >= 5) { - node = mxmlNewElement(header, "cwmp:SupportedCWMPVersions"); - if (!node) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(node, "soap_env:mustUnderstand", "0"); - node = mxmlNewOpaque(node, xml_get_cwmp_version(cwmp->conf.supported_amd_version)); - if (!node) { - MXML_DELETE(xml); - return; - } - } - - mxml_node_t *body = mxmlNewElement(envelope, "soap_env:Body"); - if (body == NULL) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *inform = mxmlNewElement(body, "cwmp:Inform"); - if (inform == NULL) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *dev_id = mxmlNewElement(inform, "DeviceId"); - if (dev_id == NULL) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *manufac = mxmlNewElement(dev_id, "Manufacturer"); - if (manufac == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(manufac, cwmp->deviceid.manufacturer ? cwmp->deviceid.manufacturer : "")) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *oui = mxmlNewElement(dev_id, "OUI"); - if (oui == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(oui, cwmp->deviceid.oui ? cwmp->deviceid.oui : "")) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *prod_class = mxmlNewElement(dev_id, "ProductClass"); - if (prod_class == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(prod_class, cwmp->deviceid.productclass ? cwmp->deviceid.productclass : "")) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *sl_no = mxmlNewElement(dev_id, "SerialNumber"); - if (sl_no == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(sl_no, cwmp->deviceid.serialnumber ? cwmp->deviceid.serialnumber : "")) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *event = mxmlNewElement(inform, "Event"); - if (event == NULL) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(event, "soap_enc:arrayType", "cwmp:EventStruct[0]"); - - cwmp->is_boot = false; - if (xml_prepare_events_inform(event, session)) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *max_env = mxmlNewElement(inform, "MaxEnvelopes"); - if (max_env == NULL) { - MXML_DELETE(xml); - return; - } - - mxmlNewInteger(max_env, 1); - - mxml_node_t *curr_time = mxmlNewElement(inform, "CurrentTime"); - if (curr_time == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(curr_time, get_time(time(NULL)))) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *retry_count = mxmlNewElement(inform, "RetryCount"); - if (retry_count == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewInteger(retry_count, cwmp->retry_count_session)) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *param_list = mxmlNewElement(inform, "ParameterList"); - if (param_list == NULL) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(param_list, "soap_enc:arrayType", "cwmp:ParameterValueStruct[0]"); - - struct list_head *ilist, *jlist; - struct cwmp_dm_parameter *dm_parameter; - int size = 0; - - list_for_each (ilist, &(session->head_event_container)) { - struct event_container *event_container = list_entry(ilist, struct event_container, list); - list_for_each (jlist, &(event_container->head_dm_parameter)) { - dm_parameter = list_entry(jlist, struct cwmp_dm_parameter, list); - if (xml_prepare_parameters_inform(dm_parameter, param_list, &size)) { - MXML_DELETE(xml); - return; - } - } - } - - size_t inform_parameters_nbre = sizeof(forced_inform_parameters) / sizeof(forced_inform_parameters[0]); - size_t i; - int j; - struct cwmp_dm_parameter cwmp_dm_param = { 0 }; - LIST_HEAD(list_inform); - for (i = 0; i < inform_parameters_nbre; i++) { - char *fault = cwmp_get_single_parameter_value(forced_inform_parameters[i], &cwmp_dm_param); - if (fault != NULL) - continue; - - // An empty connection url cause CDR test to break - if (strcmp(forced_inform_parameters[i], DM_CONN_REQ_URL) == 0 && cwmp_dm_param.value != NULL && strlen(cwmp_dm_param.value) == 0) { - CWMP_LOG(ERROR, "# Empty CR URL[%s] value", forced_inform_parameters[i]); - MXML_DELETE(xml); - return; - } - - if (xml_prepare_parameters_inform(&cwmp_dm_param, param_list, &size)) { - MXML_DELETE(xml); - return; - } - } - - for (j = 0; j < nbre_custom_inform; j++) { - char *fault = cwmp_get_single_parameter_value(custom_forced_inform_parameters[j], &cwmp_dm_param); - if (fault != NULL) - continue; - if (xml_prepare_parameters_inform(&cwmp_dm_param, param_list, &size)) { - MXML_DELETE(xml); - return; - } - } - - if (cwmp->is_boot == true) { - for (j = 0; j < nbre_boot_inform; j++) { - char *fault = cwmp_get_single_parameter_value(boot_inform_parameters[j], &cwmp_dm_param); - if (fault != NULL) - continue; - if (xml_prepare_parameters_inform(&cwmp_dm_param, param_list, &size)) { - MXML_DELETE(xml); - return; - } - } - } - - char c[256] = {0}; - if (snprintf(c, sizeof(c), "cwmp:ParameterValueStruct[%d]", size) == -1) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(param_list, "xsi:type", "soap_enc:Array"); - mxmlElementSetAttr(param_list, "soap_enc:arrayType", c); - - *tree = xml; -} - -int cwmp_rpc_acs_prepare_message_inform(struct cwmp *cwmp, struct session *session, struct rpc *this __attribute__((unused))) -{ - mxml_node_t *tree; - - if (session == NULL) - return -1; - - load_inform_xml_schema(&tree, cwmp, session); - - if (!tree) - goto error; - - session->tree_out = tree; - - return 0; - -error: - CWMP_LOG(ERROR, "Unable Prepare Message Inform", CWMP_BKP_FILE); - return -1; -} - -int cwmp_rpc_acs_parse_response_inform(struct cwmp *cwmp, struct session *session, struct rpc *this __attribute__((unused))) -{ - mxml_node_t *tree, *b; - int i = -1; - char *c; - const char *cwmp_urn; - - tree = session->tree_in; - if (!tree) - goto error; - b = mxmlFindElement(tree, tree, "MaxEnvelopes", NULL, NULL, MXML_DESCEND); - if (!b) - goto error; - b = mxmlWalkNext(b, tree, MXML_DESCEND_FIRST); - if (!b || mxmlGetType(b) != MXML_OPAQUE || !mxmlGetOpaque(b)) - goto error; - if (cwmp->conf.supported_amd_version == 1) { - cwmp->conf.amd_version = 1; - return 0; - } - b = mxmlFindElement(tree, tree, "UseCWMPVersion", NULL, NULL, MXML_DESCEND); - if (b && cwmp->conf.supported_amd_version >= 5) { //IF supported version !=5 acs response dosen't contain UseCWMPVersion - b = mxmlWalkNext(b, tree, MXML_DESCEND_FIRST); - if (!b || mxmlGetType(b) != MXML_OPAQUE || !mxmlGetOpaque(b)) - goto error; - c = (char *) mxmlGetOpaque(b); - if (c && *(c + 1) == '.') { - c += 2; - cwmp->conf.amd_version = atoi(c) + 1; - return 0; - } - goto error; - } - for (i = 0; cwmp_urls[i] != NULL; i++) { - cwmp_urn = cwmp_urls[i]; - c = (char *)xml__get_attribute_name_by_value(tree, cwmp_urn); - if (c && *(c + 5) == ':') { - break; - } - } - if (i == 0) { - cwmp->conf.amd_version = i + 1; - } else if (i >= 1 && i <= 3) { - switch (cwmp->conf.supported_amd_version) { - case 1: - cwmp->conf.amd_version = 1; //Already done - break; - case 2: - case 3: - case 4: - //MIN ACS CPE - if (cwmp->conf.supported_amd_version <= i + 1) - cwmp->conf.amd_version = cwmp->conf.supported_amd_version; - else - cwmp->conf.amd_version = i + 1; - break; - //(cwmp->supported_conf.amd_version < i+1) ?"cwmp->conf.amd_version":"i+1"; - case 5: - cwmp->conf.amd_version = i + 1; - break; - } - } else if (i >= 4) { - cwmp->conf.amd_version = cwmp->conf.supported_amd_version; - } - return 0; - -error: - return -1; -} - -int set_rpc_acs_to_supported(char *rpc_name) -{ - int i; - - for (i=1; i < __RPC_ACS_MAX; i++) { - if (strcmp(rpc_acs_methods[i].name, rpc_name) == 0) { - rpc_acs_methods[i].acs_support = RPC_ACS_SUPPORT; - return i; - } - } - return -1; -} - -void set_not_known_acs_support() -{ - int i; - for (i=1; i < __RPC_ACS_MAX; i++) { - if ((i != RPC_ACS_INFORM) && (rpc_acs_methods[i].acs_support == NOT_KNOWN)) - rpc_acs_methods[i].acs_support = RPC_ACS_NOT_SUPPORT; - } -} - -int cwmp_rpc_acs_parse_response_get_rpc_methods(struct cwmp *cwmp __attribute__((unused)), struct session *session, struct rpc *this __attribute__((unused))) -{ - mxml_node_t *tree, *b; - tree = session->tree_in; - b = mxmlFindElement(tree, tree, "cwmp:GetRPCMethodsResponse", NULL, NULL, MXML_DESCEND); - if (!b) - goto error; - - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent_node = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - - if (node_type == MXML_OPAQUE && mxmlGetType(parent_node) == MXML_ELEMENT && node_opaque && strcmp((char *) mxmlGetElement(parent_node), "string") == 0) - set_rpc_acs_to_supported((char*)node_opaque); - - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } - set_not_known_acs_support(); - return 0; -error: - return -1; -} - -int cwmp_rpc_acs_destroy_data_inform(struct session *session __attribute__((unused)), struct rpc *rpc __attribute__((unused))) -{ - //event_remove_all_event_container(session,RPC_SEND); - return 0; -} - -/* - * [RPC ACS]: GetRPCMethods - */ - -int cwmp_rpc_acs_prepare_get_rpc_methods(struct cwmp *cwmp, struct session *session, struct rpc *rpc __attribute__((unused))) -{ - mxml_node_t *tree, *n; - - load_response_xml_schema(&tree); - if (!tree) - return -1; - - n = mxmlFindElement(tree, tree, "soap_env:Envelope", NULL, NULL, MXML_DESCEND); - if (!n) - return -1; - mxmlElementSetAttr(n, "xmlns:cwmp", cwmp_urls[(cwmp->conf.amd_version) - 1]); - n = mxmlFindElement(tree, tree, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!n) - return -1; - - n = mxmlNewElement(n, "cwmp:GetRPCMethods"); - if (!n) - return -1; - - session->tree_out = tree; - - return 0; -} - -/* - * [RPC ACS]: TransferComplete - */ - -int cwmp_rpc_acs_prepare_transfer_complete(struct cwmp *cwmp, struct session *session, struct rpc *rpc) -{ - mxml_node_t *tree, *n; - struct transfer_complete *p; - - p = (struct transfer_complete *)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->conf.amd_version) - 1]); - - n = mxmlFindElement(tree, tree, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!n) - goto error; - - n = mxmlNewElement(n, "cwmp:TransferComplete"); - if (!n) - goto error; - - n = mxmlNewElement(n, "CommandKey"); - if (!n) - goto error; - - n = mxmlNewOpaque(n, p->command_key ? p->command_key : ""); - if (!n) - goto error; - - n = mxmlGetParent(n); - if (n) - n = mxmlGetParent(n); - - n = mxmlNewElement(n, "StartTime"); - if (!n) - goto error; - - n = mxmlNewOpaque(n, p->start_time); - if (!n) - goto error; - - //n = n->parent->parent; - n = mxmlGetParent(n); - if (n) - n = mxmlGetParent(n); - n = mxmlNewElement(n, "CompleteTime"); - if (!n) - goto error; - - n = mxmlNewOpaque(n, get_time(time(NULL))); - if (!n) - goto error; - - // n = n->parent->parent; - n = mxmlGetParent(n); - if (n) - n = mxmlGetParent(n); - n = mxmlNewElement(n, "FaultStruct"); - if (!n) - goto error; - - n = mxmlNewElement(n, "FaultCode"); - if (!n) - goto error; - - n = mxmlNewOpaque(n, p->fault_code ? FAULT_CPE_ARRAY[p->fault_code].CODE : "0"); - if (!n) - goto error; - - // n = n->parent->parent; - n = mxmlGetParent(n); - if (n) - n = mxmlGetParent(n); - n = mxmlNewElement(n, "FaultString"); - if (!n) - goto error; - - n = mxmlNewOpaque(n, p->fault_code ? FAULT_CPE_ARRAY[p->fault_code].DESCRIPTION : ""); - if (!n) - goto error; - - session->tree_out = tree; - - return 0; - -error: - return -1; -} - -/* - * [RPC ACS]: DUStateChangeComplete - */ - -int cwmp_rpc_acs_prepare_du_state_change_complete(struct cwmp *cwmp, struct session *session, struct rpc *rpc) -{ - mxml_node_t *tree, *n, *b, *t; - struct du_state_change_complete *p; - struct opresult *q; - char *c; - - p = (struct du_state_change_complete *)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->conf.amd_version) - 1]); - n = mxmlFindElement(tree, tree, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!n) - goto error; - - n = mxmlNewElement(n, "cwmp:DUStateChangeComplete"); - if (!n) - goto error; - - n = mxmlNewElement(n, "CommandKey"); - if (!n) - goto error; - - n = mxmlNewOpaque(n, p->command_key); - if (!n) - goto error; - // n = n->parent->parent; - n = mxmlGetParent(n); - if (n) - n = mxmlGetParent(n); - n = mxmlGetParent(n); - if (n) - n = mxmlGetParent(n); - n = mxmlNewElement(n, "Results"); - if (!n) - goto error; - - list_for_each_entry (q, &(p->list_opresult), list) { - t = mxmlNewElement(n, "OpResultStruct"); - if (!t) - goto error; - - b = mxmlNewElement(t, "UUID"); - if (!b) - goto error; - - c = q->uuid ? strdup(q->uuid) : strdup(""); - b = mxmlNewOpaque(b, c); - FREE(c); - if (!b) - goto error; - - b = mxmlNewElement(t, "DeploymentUnitRef"); - if (!b) - goto error; - - c = q->du_ref ? strdup(q->du_ref) : strdup(""); - b = mxmlNewOpaque(b, c); - FREE(c); - if (!b) - goto error; - - b = mxmlNewElement(t, "Version"); - if (!b) - goto error; - - c = q->version ? strdup(q->version) : strdup(""); - b = mxmlNewOpaque(b, c); - FREE(c); - if (!b) - goto error; - - b = mxmlNewElement(t, "CurrentState"); - if (!b) - goto error; - - c = q->current_state ? strdup(q->current_state) : strdup(""); - b = mxmlNewOpaque(b, c); - FREE(c); - if (!b) - goto error; - - b = mxmlNewElement(t, "StartTime"); - if (!b) - goto error; - - c = q->start_time ? strdup(q->start_time) : strdup(""); - b = mxmlNewOpaque(b, c); - FREE(c); - if (!b) - goto error; - - b = mxmlNewElement(t, "CompleteTime"); - if (!b) - goto error; - - c = q->complete_time ? strdup(q->complete_time) : strdup(""); - b = mxmlNewOpaque(b, c); - FREE(c); - if (!b) - goto error; - - b = mxmlNewElement(t, "FaultStruct"); - if (!b) - goto error; - - b = mxmlNewElement(b, "FaultCode"); - if (!b) - goto error; - - b = mxmlNewOpaque(b, q->fault ? FAULT_CPE_ARRAY[q->fault].CODE : "0"); - if (!b) - goto error; - - // b = b->parent->parent; - b = mxmlGetParent(b); - if (b) - b = mxmlGetParent(b); - b = mxmlNewElement(b, "FaultString"); - if (!b) - goto error; - - b = mxmlNewOpaque(b, q->fault ? FAULT_CPE_ARRAY[q->fault].DESCRIPTION : ""); - if (!b) - goto error; - } - session->tree_out = tree; - return 0; - -error: - return -1; -} - -/* - * [RPC CPE]: GetParameterValues - */ - -int cwmp_handle_rpc_cpe_get_parameter_values(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *parameter_list, *b; - char *parameter_name = NULL; - int counter = 0, fault_code = FAULT_CPE_INTERNAL_ERROR; -#ifdef ACS_MULTI - char c[256] = {0}; -#endif - LIST_HEAD(parameters_list); - - b = session->body_in; - if (session->tree_out == NULL) - goto fault; - - n = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!n) - goto fault; - - n = mxmlNewElement(n, "cwmp:GetParameterValuesResponse"); - if (!n) - goto fault; - - parameter_list = mxmlNewElement(n, "ParameterList"); - if (!parameter_list) - goto fault; -#ifdef ACS_MULTI - mxmlElementSetAttr(parameter_list, "xsi:type", "soap_enc:Array"); -#endif - while (b) { - const char *node_value = mxmlGetOpaque(b); - const char *node_name = (char *) mxmlGetElement(b); - mxml_node_t *parent_node = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - mxml_node_t *firstchild = mxmlGetFirstChild(b); - if (node_type == MXML_OPAQUE && mxmlGetType(parent_node) == MXML_ELEMENT && node_value && !strcmp((char *) mxmlGetElement(parent_node), "string")) { - parameter_name = icwmp_strdup(node_value); - } - if (node_type == MXML_ELEMENT && /* added in order to support GetParameterValues with empty string*/ - node_name != NULL && !strcmp(node_name, "string") && !firstchild) { - parameter_name = icwmp_strdup(""); - } - if (parameter_name) { - char *err = cwmp_get_parameter_values(parameter_name, ¶meters_list); - if (err && !is_obj_excluded(parameter_name)) { - fault_code = cwmp_get_fault_code_by_string(err); - goto fault; - } - struct cwmp_dm_parameter *param_value; - list_for_each_entry (param_value, ¶meters_list, list) { - n = mxmlNewElement(parameter_list, "ParameterValueStruct"); - if (!n) - goto fault; - - n = mxmlNewElement(n, "Name"); - if (!n) - goto fault; - - n = mxmlNewOpaque(n, param_value->name ? param_value->name : ""); - if (!n) - goto fault; - - n = mxmlGetParent(n); - if (!n) - goto fault; - - n = mxmlGetParent(n); - if (!n) - goto fault; - - n = mxmlNewElement(n, "Value"); - if (!n) - goto fault; - -#ifdef ACS_MULTI - mxmlElementSetAttr(n, "xsi:type", param_value->type ? param_value->type : ""); -#endif - - n = mxmlNewOpaque(n, param_value->value ? param_value->value : ""); - if (!n) - goto fault; - - counter++; - } - cwmp_free_all_dm_parameter_list(¶meters_list); - parameter_name = NULL; - } - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } - -#ifdef ACS_MULTI - b = mxmlFindElement(session->tree_out, session->tree_out, "ParameterList", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - if (snprintf(c, sizeof(c), "cwmp:ParameterValueStruct[%d]", counter) == -1) - goto fault; - - mxmlElementSetAttr(b, "soap_enc:arrayType", c); -#endif - - return 0; - -fault: - cwmp_free_all_dm_parameter_list(¶meters_list); - if (cwmp_create_fault_message(session, rpc, fault_code)) - return -1; - return 0; -} - -/* - * [RPC CPE]: GetParameterNames - */ -int cwmp_handle_rpc_cpe_get_parameter_names(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *parameter_list, *b = session->body_in; - char *parameter_name = NULL; - char *NextLevel = NULL; - int counter = 0, fault_code = FAULT_CPE_INTERNAL_ERROR; - LIST_HEAD(parameters_list); -#ifdef ACS_MULTI - char c[256] = {0}; -#endif - if (session->tree_out == NULL) - goto fault; - - n = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!n) - goto fault; - - n = mxmlNewElement(n, "cwmp:GetParameterNamesResponse"); - if (!n) - goto fault; - - parameter_list = mxmlNewElement(n, "ParameterList"); - if (!parameter_list) - goto fault; - -#ifdef ACS_MULTI - mxmlElementSetAttr(parameter_list, "xsi:type", "soap_enc:Array"); -#endif - - while (b) { - const char *node_value = mxmlGetOpaque(b); - const char *node_name = (char *) mxmlGetElement(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - mxml_node_t *firstchild = mxmlGetFirstChild(b); - - if (node_type == MXML_OPAQUE && node_value && mxmlGetType(parent) == MXML_ELEMENT && !strcmp((char *) mxmlGetElement(parent), "ParameterPath")) { - parameter_name = icwmp_strdup(node_value); - } - if (node_type == MXML_ELEMENT && node_name && !strcmp(node_name, "ParameterPath") && !firstchild) { - parameter_name = icwmp_strdup(""); - } - if (node_type == MXML_OPAQUE && node_value && mxmlGetType(parent) == MXML_ELEMENT && !strcmp((char *) mxmlGetElement(parent), "NextLevel")) { - NextLevel = icwmp_strdup(node_value); - } - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } - - if (!icwmp_validate_boolean_value(NextLevel)) { - fault_code = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - - if (parameter_name && NextLevel) { - char *err = cwmp_get_parameter_names(parameter_name, strcmp(NextLevel, "true") == 0 || strcmp(NextLevel, "1") == 0 ? true : false, ¶meters_list); - if (err && !is_obj_excluded(parameter_name)) { - fault_code = cwmp_get_fault_code_by_string(err); - goto fault; - } - parameter_name = NULL; - NextLevel = NULL; - } - struct cwmp_dm_parameter *param_value; - list_for_each_entry (param_value, ¶meters_list, list) { - n = mxmlNewElement(parameter_list, "ParameterInfoStruct"); - if (!n) - goto fault; - - n = mxmlNewElement(n, "Name"); - if (!n) - goto fault; - - n = mxmlNewOpaque(n, param_value->name); - if (!n) - goto fault; - - n = mxmlGetParent(n); - if (!n) - goto fault; - - n = mxmlGetParent(n); - if (!n) - goto fault; - - n = mxmlNewElement(n, "Writable"); - if (!n) - goto fault; - - n = mxmlNewOpaque(n, param_value->writable ? "1" : "0"); - if (!n) - goto fault; - - counter++; - } - cwmp_free_all_dm_parameter_list(¶meters_list); -#ifdef ACS_MULTI - b = mxmlFindElement(session->tree_out, session->tree_out, "ParameterList", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - if (snprintf(c, sizeof(c), "cwmp:ParameterInfoStruct[%d]", counter) == -1) - goto fault; - - mxmlElementSetAttr(b, "soap_enc:arrayType", c); -#endif - return 0; - -fault: - cwmp_free_all_dm_parameter_list(¶meters_list); - if (cwmp_create_fault_message(session, rpc, fault_code)) - return -1; - return 0; -} - -/* - * [RPC CPE]: GetParameterAttributes - */ - -int cwmp_handle_rpc_cpe_get_parameter_attributes(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *parameter_list, *b; - char *parameter_name = NULL; - int counter = 0, fault_code = FAULT_CPE_INTERNAL_ERROR; - LIST_HEAD(parameters_list); -#ifdef ACS_MULTI - char c[256]; -#endif - b = session->body_in; - n = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!n) - goto fault; - - n = mxmlNewElement(n, "cwmp:GetParameterAttributesResponse"); - if (!n) - goto fault; - - parameter_list = mxmlNewElement(n, "ParameterList"); - if (!parameter_list) - goto fault; - -#ifdef ACS_MULTI - mxmlElementSetAttr(parameter_list, "xsi:type", "soap_enc:Array"); -#endif - - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - const char *node_name = (char *) mxmlGetElement(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - mxml_node_t *firstchild = mxmlGetFirstChild(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "string")) { - parameter_name = icwmp_strdup(node_opaque); - } - if (node_type == MXML_ELEMENT && !strcmp(node_name, "string") && !firstchild) { - parameter_name = icwmp_strdup(""); - } - if (parameter_name) { - char *err = cwmp_get_parameter_attributes(parameter_name, ¶meters_list); - if (err && !is_obj_excluded(parameter_name)) { - fault_code = cwmp_get_fault_code_by_string(err); - goto fault; - } - struct cwmp_dm_parameter *param_value; - list_for_each_entry (param_value, ¶meters_list, list) { - n = mxmlNewElement(parameter_list, "ParameterAttributeStruct"); - if (!n) - goto fault; - - n = mxmlNewElement(n, "Name"); - if (!n) - goto fault; - - n = mxmlNewOpaque(n, param_value->name); - if (!n) - goto fault; - - n = mxmlGetParent(n); - if (n) - n = mxmlGetParent(n); - n = mxmlNewElement(n, "Notification"); - if (!n) - goto fault; - - char notification[2]; - snprintf(notification, sizeof(notification), "%d", param_value->notification); - n = mxmlNewOpaque(n, notification); - if (!n) - goto fault; - - n = mxmlGetParent(n); - if (n) - n = mxmlGetParent(n); - n = mxmlNewElement(n, "AccessList"); - if (!n) - goto fault; - - n = mxmlNewOpaque(n, ""); - if (!n) - goto fault; - - counter++; - } - cwmp_free_all_dm_parameter_list(¶meters_list); - parameter_name = NULL; - } - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } -#ifdef ACS_MULTI - b = mxmlFindElement(session->tree_out, session->tree_out, "ParameterList", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - if (snprintf(c, sizeof(c), "cwmp:ParameterAttributeStruct[%d]", counter) == -1) - goto fault; - - mxmlElementSetAttr(b, "soap_enc:arrayType", c); -#endif - return 0; - -fault: - cwmp_free_all_dm_parameter_list(¶meters_list); - if (cwmp_create_fault_message(session, rpc, fault_code)) - return -1; - return 0; -} - -/* - * [RPC CPE]: SetParameterValues - */ - -static int is_duplicated_parameter(mxml_node_t *param_node, struct session *session) -{ - mxml_node_t *b = param_node; - while ((b = mxmlWalkNext(b, session->body_in, MXML_DESCEND))) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Name")) { - if (strcmp(node_opaque, mxmlGetOpaque(param_node)) == 0) - return -1; - } - } - return 0; -} - -int cwmp_handle_rpc_cpe_set_parameter_values(struct session *session, struct rpc *rpc) -{ - mxml_node_t *b = NULL; - char *parameter_name = NULL; - char *parameter_value = NULL; - char *parameter_key = NULL; - char *v, *c = NULL; - int fault_code = FAULT_CPE_INTERNAL_ERROR, ret = 0; - - b = mxmlFindElement(session->body_in, session->body_in, "ParameterList", NULL, NULL, MXML_DESCEND); - if (!b) { - fault_code = FAULT_CPE_REQUEST_DENIED; - goto fault; - } - - LIST_HEAD(list_fault_param); - rpc->list_set_value_fault = &list_fault_param; - LIST_HEAD(list_set_param_value); - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - const char *node_name = (char *) mxmlGetElement(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - mxml_node_t *child = mxmlGetFirstChild(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Name")) { - parameter_name = icwmp_strdup(node_opaque); - if (is_duplicated_parameter(b, session)) { - fault_code = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - } - - if (node_type == MXML_ELEMENT && !strcmp(node_name, "Name") && !child) { - parameter_name = icwmp_strdup(""); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Value")) { - parameter_value = icwmp_strdup((char *)mxmlGetOpaque(b)); - while ((b = mxmlWalkNext(b, parent, MXML_DESCEND))) { - v = (char *)mxmlGetOpaque(b); - icwmp_asprintf(&c, "%s %s", parameter_value, v); - parameter_value = icwmp_strdup(c); - } - b = mxmlGetLastChild(parent); - } - if (node_type == MXML_ELEMENT && !strcmp(node_name, "Value") && !child) { - parameter_value = icwmp_strdup(""); - } - if (parameter_name && parameter_value) { - add_dm_parameter_to_list(&list_set_param_value, parameter_name, parameter_value, NULL, 0, false); - parameter_name = NULL; - parameter_value = NULL; - } - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } - - b = mxmlFindElement(session->body_in, session->body_in, "ParameterKey", NULL, NULL, MXML_DESCEND); - if (!b) { - fault_code = FAULT_CPE_REQUEST_DENIED; - goto fault; - } - b = mxmlWalkNext(b, session->tree_in, MXML_DESCEND_FIRST); - if (b && mxmlGetType(b) == MXML_OPAQUE && mxmlGetOpaque(b)) - parameter_key = icwmp_strdup(mxmlGetOpaque(b)); - - if (!icwmp_validate_string_length(parameter_key, 32)) { - fault_code = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - - int flag = 0; - if (transaction_id == 0) { - if (!cwmp_transaction_start("cwmp")) - goto fault; - } - fault_code = cwmp_set_multiple_parameters_values(&list_set_param_value, parameter_key ? parameter_key : "", &flag, rpc->list_set_value_fault); - if (fault_code != FAULT_CPE_NO_FAULT) - goto fault; - - struct cwmp_dm_parameter *param_value; - list_for_each_entry (param_value, &list_set_param_value, list) { - set_interface_reset_request(param_value->name, param_value->value); - set_diagnostic_parameter_structure_value(param_value->name, param_value->value); - } - - cwmp_free_all_dm_parameter_list(&list_set_param_value); - - b = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - b = mxmlNewElement(b, "cwmp:SetParameterValuesResponse"); - if (!b) - goto fault; - - b = mxmlNewElement(b, "Status"); - if (!b) - goto fault; - - b = mxmlNewOpaque(b, "1"); - if (!b) - goto fault; - - if (!cwmp_transaction_commit()) - goto fault; - - cwmp_set_end_session(flag | END_SESSION_RESTART_SERVICES | END_SESSION_SET_NOTIFICATION_UPDATE | END_SESSION_RELOAD); - return 0; - -fault: - cwmp_free_all_dm_parameter_list(&list_set_param_value); - if (cwmp_create_fault_message(session, rpc, fault_code)) - ret = CWMP_XML_ERR; - - cwmp_free_all_list_param_fault(rpc->list_set_value_fault); - if (transaction_id) { - cwmp_transaction_abort(); - transaction_id = 0; - } - return ret; -} - -/* - * [RPC CPE]: SetParameterAttributes - */ - -int cwmp_handle_rpc_cpe_set_parameter_attributes(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *b = session->body_in; - char *parameter_name = NULL, *parameter_notification = NULL; - int fault_code = FAULT_CPE_INTERNAL_ERROR, ret = 0; - char *notification_change = NULL; - char c[256]; - - /* handle cwmp:SetParameterAttributes */ - if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "SetParameterAttributes") == -1) - goto fault; - - n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); - - if (!n) - goto fault; - b = n; - - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - const char *node_name = (char *) mxmlGetElement(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - mxml_node_t *child = mxmlGetFirstChild(b); - - if (node_type == MXML_ELEMENT && !strcmp(node_name, "SetParameterAttributesStruct")) { - parameter_name = NULL; - parameter_notification = NULL; - notification_change = NULL; - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Name")) { - parameter_name = icwmp_strdup(node_opaque); - } - if (node_type == MXML_ELEMENT && !strcmp(node_name, "Name") && !child) { - parameter_name = icwmp_strdup(""); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "NotificationChange")) { - notification_change = icwmp_strdup(node_opaque); - } - if (node_type == MXML_ELEMENT && !strcmp(node_name, "NotificationChange") && !child) { - notification_change = icwmp_strdup(""); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Notification")) { - parameter_notification = icwmp_strdup(node_opaque); - } - if (node_type == MXML_ELEMENT && !strcmp(node_name, "Notification") && !child) { - parameter_notification = icwmp_strdup(""); - } - if (parameter_name && parameter_notification && notification_change) { - if (!icwmp_validate_boolean_value(notification_change)) { - fault_code = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_int_in_range(parameter_notification, 0, 6)) { - fault_code = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - char *err = cwmp_set_parameter_attributes(parameter_name, atoi(parameter_notification)); - if (err) { - fault_code = cwmp_get_fault_code_by_string(err); - goto fault; - } - parameter_name = NULL; - parameter_notification = NULL; - notification_change = NULL; - } - b = mxmlWalkNext(b, n, MXML_DESCEND); - } - - b = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - b = mxmlNewElement(b, "cwmp:SetParameterAttributesResponse"); - if (!b) - goto fault; - - cwmp_set_end_session(END_SESSION_SET_NOTIFICATION_UPDATE | END_SESSION_RESTART_SERVICES | END_SESSION_INIT_NOTIFY); - return 0; - -fault: - if (cwmp_create_fault_message(session, rpc, fault_code)) - ret = CWMP_XML_ERR; - - return ret; -} - -/* - * [RPC CPE]: AddObject - */ - -int cwmp_handle_rpc_cpe_add_object(struct session *session, struct rpc *rpc) -{ - mxml_node_t *b; - char *object_name = NULL; - char *parameter_key = NULL; - int fault_code = FAULT_CPE_INTERNAL_ERROR, ret = 0; - char *instance = NULL; - - b = session->body_in; - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "ParameterKey")) { - parameter_key = icwmp_strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "ObjectName")) { - object_name = icwmp_strdup(node_opaque); - } - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } - - if (!icwmp_validate_string_length(parameter_key, 32)) { - fault_code = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (transaction_id == 0) { - if (!cwmp_transaction_start("cwmp")) - goto fault; - } - - if (object_name) { - char *err = cwmp_add_object(object_name, parameter_key ? parameter_key : "", &instance); - if (err) { - fault_code = cwmp_get_fault_code_by_string(err); - goto fault; - } - - if (instance == NULL) { - fault_code = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - } else { - fault_code = FAULT_CPE_INVALID_PARAMETER_NAME; - goto fault; - } - - b = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - b = mxmlNewElement(b, "cwmp:AddObjectResponse"); - if (!b) - goto fault; - - b = mxmlNewElement(b, "InstanceNumber"); - if (!b) - goto fault; - - b = mxmlNewOpaque(b, instance); - if (!b) - goto fault; - - b = mxmlGetParent(b); - if (!b) - goto fault; - - b = mxmlGetParent(b); - if (!b) - goto fault; - - b = mxmlNewElement(b, "Status"); - if (!b) - goto fault; - - b = mxmlNewOpaque(b, "1"); - if (!b) - goto fault; - - if (!cwmp_transaction_commit()) - goto fault; - - char *object_path = NULL; - icwmp_asprintf(&object_path, "%s%s.", object_name, instance); - cwmp_set_parameter_attributes(object_path, 0); - FREE(instance); - cwmp_set_end_session(END_SESSION_RESTART_SERVICES); - return 0; - -fault: - FREE(instance); - if (cwmp_create_fault_message(session, rpc, fault_code)) - ret = CWMP_XML_ERR; - if (transaction_id) { - cwmp_transaction_abort(); - transaction_id = 0; - } - return ret; -} - -/* - * [RPC CPE]: DeleteObject - */ - -int cwmp_handle_rpc_cpe_delete_object(struct session *session, struct rpc *rpc) -{ - mxml_node_t *b; - char *object_name = NULL; - char *parameter_key = NULL; - int fault_code = FAULT_CPE_INTERNAL_ERROR, ret = 0; - - b = session->body_in; - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "ObjectName")) { - object_name = icwmp_strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "ParameterKey")) { - parameter_key = icwmp_strdup(node_opaque); - } - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } - if (!icwmp_validate_string_length(parameter_key, 32)) { - fault_code = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (transaction_id == 0) { - if (!cwmp_transaction_start("cwmp")) - goto fault; - } - if (object_name) { - char *err = cwmp_delete_object(object_name, parameter_key ? parameter_key : ""); - if (err) { - fault_code = cwmp_get_fault_code_by_string(err); - goto fault; - } - } else { - fault_code = FAULT_CPE_INVALID_PARAMETER_NAME; - goto fault; - } - - b = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - b = mxmlNewElement(b, "cwmp:DeleteObjectResponse"); - if (!b) - goto fault; - - b = mxmlNewElement(b, "Status"); - if (!b) - goto fault; - - b = mxmlNewOpaque(b, "1"); - if (!b) - goto fault; - - if (!cwmp_transaction_commit()) - goto fault; - - cwmp_set_end_session(END_SESSION_RESTART_SERVICES); - return 0; - -fault: - if (cwmp_create_fault_message(session, rpc, fault_code)) - ret = CWMP_XML_ERR; - if (transaction_id) { - cwmp_transaction_abort(); - transaction_id = 0; - } - return ret; -} - -/* - * [RPC CPE]: GetRPCMethods - */ - -int cwmp_handle_rpc_cpe_get_rpc_methods(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *method_list; - int i, counter = 0; -#ifdef ACS_MULTI - mxml_node_t *b = session->body_in; - char c[128]; -#endif - - n = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!n) - goto fault; - - n = mxmlNewElement(n, "cwmp:GetRPCMethodsResponse"); - if (!n) - goto fault; - - method_list = mxmlNewElement(n, "MethodList"); - if (!method_list) - goto fault; - - for (i = 1; i < __RPC_CPE_MAX; i++) { - if (i != RPC_CPE_FAULT) { - n = mxmlNewElement(method_list, "string"); - if (!n) - goto fault; - - n = mxmlNewOpaque(n, rpc_cpe_methods[i].name); - if (!n) - goto fault; - - counter++; - } - } -#ifdef ACS_MULTI - b = mxmlFindElement(session->tree_out, session->tree_out, "MethodList", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - mxmlElementSetAttr(b, "xsi:type", "soap_enc:Array"); - if (snprintf(c, sizeof(c), "xsd:string[%d]", counter) == -1) - goto fault; - - mxmlElementSetAttr(b, "soap_enc:arrayType", c); -#endif - - return 0; - -fault: - if (cwmp_create_fault_message(session, rpc, FAULT_CPE_INTERNAL_ERROR)) - goto error; - return 0; - -error: - return -1; -} - -/* - * [RPC CPE]: FactoryReset - */ - -int cwmp_handle_rpc_cpe_factory_reset(struct session *session, struct rpc *rpc) -{ - mxml_node_t *b; - - b = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - b = mxmlNewElement(b, "cwmp:FactoryResetResponse"); - if (!b) - goto fault; - - cwmp_set_end_session(END_SESSION_FACTORY_RESET); - - return 0; - -fault: - if (cwmp_create_fault_message(session, rpc, FAULT_CPE_INTERNAL_ERROR)) - goto error; - return 0; - -error: - return -1; -} - -/* - * [RPC CPE]: X_FactoryResetSoft - */ - -int cwmp_handle_rpc_cpe_x_factory_reset_soft(struct session *session, struct rpc *rpc) -{ - mxml_node_t *b; - - b = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - b = mxmlNewElement(b, "cwmp:X_FactoryResetSoftResponse"); - if (!b) - goto fault; - - cwmp_set_end_session(END_SESSION_X_FACTORY_RESET_SOFT); - - return 0; - -fault: - if (cwmp_create_fault_message(session, rpc, FAULT_CPE_INTERNAL_ERROR)) - goto error; - return 0; - -error: - return -1; -} - -/* - * [RPC CPE]: CancelTransfer - */ - -int cwmp_handle_rpc_cpe_cancel_transfer(struct session *session, struct rpc *rpc) -{ - mxml_node_t *b; - char *command_key = NULL; - int fault_code = FAULT_CPE_INTERNAL_ERROR; - - b = session->body_in; - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "CommandKey")) { - command_key = icwmp_strdup(node_opaque); - } - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } - if (!icwmp_validate_string_length(command_key, 32)) { - fault_code = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (command_key) { - cancel_transfer(command_key); - } - b = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - b = mxmlNewElement(b, "cwmp:CancelTransferResponse"); - if (!b) - goto fault; - return 0; -fault: - if (cwmp_create_fault_message(session, rpc, fault_code)) - goto error; - return 0; - -error: - return -1; -} - -int cancel_transfer(char *key) -{ - struct list_head *ilist, *q; - - if (list_download.next != &(list_download)) { - list_for_each_safe (ilist, q, &(list_download)) { - struct download *pdownload = list_entry(ilist, struct download, list); - if (strcmp(pdownload->command_key, key) == 0) { - pthread_mutex_lock(&mutex_download); - bkp_session_delete_download(pdownload); - bkp_session_save(); - list_del(&(pdownload->list)); - if (pdownload->scheduled_time != 0) - count_download_queue--; - cwmp_free_download_request(pdownload); - pthread_mutex_unlock(&mutex_download); - } - } - } - if (list_upload.next != &(list_upload)) { - list_for_each_safe (ilist, q, &(list_upload)) { - struct upload *pupload = list_entry(ilist, struct upload, list); - if (strcmp(pupload->command_key, key) == 0) { - pthread_mutex_lock(&mutex_upload); - bkp_session_delete_upload(pupload); - bkp_session_save(); - list_del(&(pupload->list)); - if (pupload->scheduled_time != 0) - count_download_queue--; - cwmp_free_upload_request(pupload); - pthread_mutex_unlock(&mutex_upload); - } - } - } - // Cancel schedule download - return CWMP_OK; -} - -/* - * [RPC CPE]: Reboot - */ - -int cwmp_handle_rpc_cpe_reboot(struct session *session, struct rpc *rpc) -{ - mxml_node_t *b; - struct event_container *event_container; - char *command_key = NULL; - int fault_code = FAULT_CPE_INTERNAL_ERROR; - b = session->body_in; - - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "CommandKey")) { - command_key = icwmp_strdup(node_opaque); - commandKey = icwmp_strdup(node_opaque); - } - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } - if (!icwmp_validate_string_length(commandKey, 32)) { - fault_code = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - pthread_mutex_lock(&(cwmp_main.mutex_session_queue)); - event_container = cwmp_add_event_container(&cwmp_main, EVENT_IDX_M_Reboot, command_key); - if (event_container == NULL) { - pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); - goto fault; - } - cwmp_save_event_container(event_container); - pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); - - b = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!b) - goto fault; - - b = mxmlNewElement(b, "cwmp:RebootResponse"); - if (!b) - goto fault; - - cwmp_set_end_session(END_SESSION_REBOOT); - - return 0; - -fault: - if (cwmp_create_fault_message(session, rpc, fault_code)) - goto error; - return 0; - -error: - return -1; -} - -/* - * [RPC CPE]: ScheduleInform - */ - -int cwmp_handle_rpc_cpe_schedule_inform(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *b = session->body_in; - char *command_key = NULL; - struct schedule_inform *schedule_inform; - time_t scheduled_time; - struct list_head *ilist; - int fault = FAULT_CPE_NO_FAULT; - int delay_seconds = 0; - - pthread_mutex_lock(&mutex_schedule_inform); - - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "CommandKey")) { - command_key = icwmp_strdup(node_opaque); - } - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "DelaySeconds")) { - delay_seconds = atoi(node_opaque); - } - b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); - } - if (!icwmp_validate_string_length(command_key, 32)) { - fault = FAULT_CPE_INVALID_ARGUMENTS; - pthread_mutex_unlock(&mutex_schedule_inform); - goto fault; - } - if (delay_seconds <= 0) { - fault = FAULT_CPE_INVALID_ARGUMENTS; - pthread_mutex_unlock(&mutex_schedule_inform); - goto fault; - } - - if (count_schedule_inform_queue >= MAX_SCHEDULE_INFORM_QUEUE) { - fault = FAULT_CPE_RESOURCES_EXCEEDED; - pthread_mutex_unlock(&mutex_schedule_inform); - goto fault; - } - count_schedule_inform_queue++; - - scheduled_time = time(NULL) + delay_seconds; - list_for_each (ilist, &(list_schedule_inform)) { - schedule_inform = list_entry(ilist, struct schedule_inform, list); - if (schedule_inform->scheduled_time >= scheduled_time) { - break; - } - } - - n = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!n) - goto fault; - - n = mxmlNewElement(n, "cwmp:ScheduleInformResponse"); - if (!n) - goto fault; - - CWMP_LOG(INFO, "Schedule inform event will start in %us", delay_seconds); - schedule_inform = calloc(1, sizeof(struct schedule_inform)); - if (schedule_inform == NULL) { - pthread_mutex_unlock(&mutex_schedule_inform); - goto fault; - } - schedule_inform->commandKey = strdup(command_key); - schedule_inform->scheduled_time = scheduled_time; - list_add(&(schedule_inform->list), ilist->prev); - bkp_session_insert_schedule_inform(schedule_inform->scheduled_time, schedule_inform->commandKey); - bkp_session_save(); - pthread_mutex_unlock(&mutex_schedule_inform); - pthread_cond_signal(&threshold_schedule_inform); - -success: - return 0; - -fault: - if (cwmp_create_fault_message(session, rpc, fault ? fault : FAULT_CPE_INTERNAL_ERROR)) - goto error; - goto success; - -error: - return -1; -} - -/* - * [RPC CPE]: ChangeDuState - */ -int cwmp_handle_rpc_cpe_change_du_state(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *t, *b = session->body_in; - struct change_du_state *change_du_state = NULL; - struct operations *elem = NULL; - int error = FAULT_CPE_NO_FAULT; - char c[256]; - - if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "ChangeDUState") == -1) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - - n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); - - if (!n) - return -1; - b = n; - - change_du_state = calloc(1, sizeof(struct change_du_state)); - if (change_du_state == NULL) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - - INIT_LIST_HEAD(&(change_du_state->list_operation)); - change_du_state->timeout = time(NULL); - - while (b) { - const char *node_opaque = mxmlGetOpaque(b); - const char *node_name = (char *) mxmlGetElement(b); - mxml_type_t node_type = mxmlGetType(b); - mxml_node_t *parent = mxmlGetParent(b); - t = b; - if (node_type == MXML_ELEMENT && strcmp(node_name, "Operations") == 0) { - char *operation = (char *)mxmlElementGetAttr(b, "xsi:type"); - if (!strcmp(operation, "cwmp:InstallOpStruct")) { - elem = (operations *)calloc(1, sizeof(operations)); - elem->type = DU_INSTALL; - list_add_tail(&(elem->list), &(change_du_state->list_operation)); - t = mxmlWalkNext(t, b, MXML_DESCEND); - while (t) { - const char *opaque = mxmlGetOpaque(t); - mxml_node_t *prt = mxmlGetParent(t); - mxml_type_t type = mxmlGetType(t); - - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "URL")) { - elem->url = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "UUID")) { - elem->uuid = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "Username")) { - elem->username = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "Password")) { - elem->password = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "ExecutionEnvRef")) { - elem->executionenvref = strdup(opaque); - } - t = mxmlWalkNext(t, b, MXML_DESCEND); - } - } else if (!strcmp(operation, "cwmp:UpdateOpStruct")) { - elem = (operations *)calloc(1, sizeof(operations)); - elem->type = DU_UPDATE; - list_add_tail(&(elem->list), &(change_du_state->list_operation)); - t = mxmlWalkNext(t, b, MXML_DESCEND); - while (t) { - const char *opaque = mxmlGetOpaque(t); - mxml_node_t *prt = mxmlGetParent(t); - mxml_type_t type = mxmlGetType(t); - - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "Username")) { - elem->url = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "Version")) { - elem->uuid = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "URL")) { - elem->username = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "Password")) { - elem->password = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "UUID")) { - elem->executionenvref = strdup(opaque); - } - - t = mxmlWalkNext(t, b, MXML_DESCEND); - } - } else if (!strcmp(operation, "cwmp:UninstallOpStruct")) { - elem = (operations *)calloc(1, sizeof(operations)); - elem->type = DU_UNINSTALL; - list_add_tail(&(elem->list), &(change_du_state->list_operation)); - t = mxmlWalkNext(t, b, MXML_DESCEND); - while (t) { - const char *opaque = mxmlGetOpaque(t); - mxml_node_t *prt = mxmlGetParent(t); - mxml_type_t type = mxmlGetType(t); - - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "Version")) { - elem->url = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "ExecutionEnvRef")) { - elem->uuid = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "URL")) { - elem->username = strdup(opaque); - } - - t = mxmlWalkNext(t, b, MXML_DESCEND); - } - } - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "CommandKey")) { - change_du_state->command_key = strdup(node_opaque); - } - b = mxmlWalkNext(b, n, MXML_DESCEND); - } - if (!icwmp_validate_string_length(change_du_state->command_key, 32)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - t = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!t) - goto fault; - - t = mxmlNewElement(t, "cwmp:ChangeDUStateResponse"); - if (!t) - goto fault; - - if (error == FAULT_CPE_NO_FAULT) { - pthread_mutex_lock(&mutex_change_du_state); - list_add_tail(&(change_du_state->list), &(list_change_du_state)); - bkp_session_insert_change_du_state(change_du_state); - bkp_session_save(); - pthread_mutex_unlock(&mutex_change_du_state); - pthread_cond_signal(&threshold_change_du_state); - } - return 0; - -fault: - cwmp_free_change_du_state_request(change_du_state); - if (cwmp_create_fault_message(session, rpc, error)) - goto error; - return 0; - -error: - return -1; -} - -int create_download_upload_response(mxml_node_t *tree_out, enum load_type ltype) -{ - mxml_node_t *t, *b; - t = mxmlFindElement(tree_out, tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!t) - return -1; - - t = mxmlNewElement(t, ltype == TYPE_DOWNLOAD ? "cwmp:DownloadResponse" : "cwmp:UploadResponse"); - if (!t) - return -1; - - b = mxmlNewElement(t, "Status"); - if (!b) - return -1; - - b = mxmlNewOpaque(b, "1"); - if (!b) - return -1; - - b = mxmlGetParent(b); - if (b) - b = mxmlGetParent(b); - - b = mxmlNewElement(t, "StartTime"); - if (!b) - return -1; - - b = mxmlNewOpaque(b, "0001-01-01T00:00:00+00:00"); - if (!b) - return -1; - - b = mxmlGetParent(mxmlGetParent(b)); - b = mxmlNewElement(t, "CompleteTime"); - if (!b) - return -1; - - b = mxmlNewOpaque(b, "0001-01-01T00:00:00+00:00"); - if (!b) - return -1; - - return FAULT_CPE_NO_FAULT; -} - -/* - * [RPC CPE]: Download - */ -int cwmp_handle_rpc_cpe_download(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *b = session->body_in; - char c[256], *tmp, *file_type = NULL; - int error = FAULT_CPE_NO_FAULT; - struct download *download = NULL, *idownload; - struct list_head *ilist; - time_t scheduled_time = 0; - time_t download_delay = 0; - char *str_file_size = NULL, *str_download_delay = NULL; - - if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "Download") == -1) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - - n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); - - if (!n) - return -1; - b = n; - - download = calloc(1, sizeof(struct download)); - if (download == NULL) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - - while (b != NULL) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "CommandKey")) { - download->command_key = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "FileType")) { - if (download->file_type == NULL) { - download->file_type = strdup(node_opaque); - file_type = icwmp_strdup(node_opaque); - } else { - tmp = file_type; - if (cwmp_asprintf(&file_type, "%s %s", tmp, node_opaque) == -1) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - } - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "URL")) { - download->url = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Username")) { - download->username = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Password")) { - download->password = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "FileSize")) { - str_file_size = strdup(node_opaque ? node_opaque: "0"); - download->file_size = atoi(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "DelaySeconds")) { - str_download_delay = strdup(node_opaque ? node_opaque: "0"); - download_delay = atol(node_opaque); - } - b = mxmlWalkNext(b, n, MXML_DESCEND); - } - if (!icwmp_validate_string_length(download->command_key, 32)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_string_length(download->url, 256)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_string_length(download->username, 256)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_string_length(download->password, 256)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_unsignedint(str_file_size)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - FREE(str_file_size); - goto fault; - } - FREE(str_file_size); - if (!icwmp_validate_unsignedint(str_download_delay)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - FREE(str_download_delay); - goto fault; - } - FREE(str_download_delay); - - if (strcmp(file_type, FIRMWARE_UPGRADE_IMAGE_FILE_TYPE) && strcmp(file_type, WEB_CONTENT_FILE_TYPE) && strcmp(file_type, VENDOR_CONFIG_FILE_TYPE) && strcmp(file_type, TONE_FILE_TYPE) && strcmp(file_type, RINGER_FILE_TYPE) && strcmp(file_type, STORED_FIRMWARE_IMAGE_FILE_TYPE)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - } else if (count_download_queue >= MAX_DOWNLOAD_QUEUE) { - error = FAULT_CPE_RESOURCES_EXCEEDED; - } else if (download->url == NULL || (strcmp(download->url, "") == 0)) { - error = FAULT_CPE_REQUEST_DENIED; - } else if (strstr(download->url, "@") != NULL) { - error = FAULT_CPE_INVALID_ARGUMENTS; - } else if (strncmp(download->url, DOWNLOAD_PROTOCOL_HTTP, strlen(DOWNLOAD_PROTOCOL_HTTP)) != 0 && strncmp(download->url, DOWNLOAD_PROTOCOL_HTTPS, strlen(DOWNLOAD_PROTOCOL_HTTPS)) != 0 && strncmp(download->url, DOWNLOAD_PROTOCOL_FTP, strlen(DOWNLOAD_PROTOCOL_FTP)) != 0) { - error = FAULT_CPE_FILE_TRANSFER_UNSUPPORTED_PROTOCOL; - } - if (error != FAULT_CPE_NO_FAULT) - goto fault; - - if (create_download_upload_response(session->tree_out, TYPE_DOWNLOAD) != FAULT_CPE_NO_FAULT) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - - if (error == FAULT_CPE_NO_FAULT) { - pthread_mutex_lock(&mutex_download); - if (download_delay != 0) - scheduled_time = time(NULL) + download_delay + PROCESSING_DELAY; - - list_for_each (ilist, &(list_download)) { - idownload = list_entry(ilist, struct download, list); - if (idownload->scheduled_time >= scheduled_time) { - break; - } - } - list_add(&(download->list), ilist->prev); - if (download_delay != 0) { - count_download_queue++; - download->scheduled_time = scheduled_time; - } - bkp_session_insert_download(download); - bkp_session_save(); - if (download_delay != 0) { - CWMP_LOG(INFO, "Download will start in %us", download_delay); - } else { - CWMP_LOG(INFO, "Download will start at the end of session"); - } - - pthread_mutex_unlock(&mutex_download); - pthread_cond_signal(&threshold_download); - } - - return 0; - -fault: - cwmp_free_download_request(download); - if (cwmp_create_fault_message(session, rpc, error)) - return -1; - return 0; -} - -/* - * [RPC CPE]: ScheduleDownload - */ -int cwmp_handle_rpc_cpe_schedule_download(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *t, *b = session->body_in; - char c[256], *tmp, *file_type = NULL; - char *windowmode0 = NULL, *windowmode1 = NULL, *str_file_size = NULL; - int i = 0, j = 0; - int error = FAULT_CPE_NO_FAULT; - struct download *schedule_download = NULL; - time_t schedule_download_delay[4] = { 0, 0, 0, 0 }; - - if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "ScheduleDownload") == -1) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - - n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); - - if (!n) - return -1; - b = n; - - schedule_download = calloc(1, sizeof(struct download)); - if (schedule_download == NULL) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - - while (b != NULL) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - t = b; - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "CommandKey")) { - schedule_download->command_key = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "FileType")) { - if (schedule_download->file_type != NULL) { - tmp = file_type; - if (cwmp_asprintf(&file_type, "%s %s", tmp, node_opaque) == -1) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - } else { - schedule_download->file_type = strdup(node_opaque); - file_type = icwmp_strdup(node_opaque); - } - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "URL")) { - schedule_download->url = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Username")) { - schedule_download->username = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Password")) { - schedule_download->password = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "FileSize")) { - str_file_size = strdup(node_opaque); - schedule_download->file_size = atoi(node_opaque); - } - if (node_type== MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "TimeWindowList")) { - if (!t) - return -1; //TO CHECK*/ - t = mxmlWalkNext(t, b, MXML_DESCEND); - while (t) { - const char *opaque = mxmlGetOpaque(t); - mxml_node_t *prt = mxmlGetParent(t); - mxml_type_t type = mxmlGetType(t); - - if (type == MXML_OPAQUE && node_opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "WindowStart")) { - schedule_download_delay[j] = atol(opaque); - j++; - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "WindowEnd")) { - schedule_download_delay[j] = atol(opaque); - j++; - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "WindowMode")) { - if (schedule_download->timewindowstruct[i].windowmode == NULL) { - schedule_download->timewindowstruct[i].windowmode = strdup(opaque); - if (i == 0) - windowmode0 = icwmp_strdup(opaque); - else - windowmode1 = icwmp_strdup(opaque); - } else if (i == 0) { - tmp = windowmode0; - if (cwmp_asprintf(&windowmode0, "%s %s", tmp, opaque) == -1) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - } else if (i == 1) { - tmp = windowmode1; - if (cwmp_asprintf(&windowmode1, "%s %s", tmp, opaque) == -1) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - } - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "UserMessage")) { - schedule_download->timewindowstruct[i].usermessage = strdup(opaque); - } - if (type == MXML_OPAQUE && opaque && mxmlGetType(prt) == MXML_ELEMENT && !strcmp(mxmlGetElement(prt), "MaxRetries")) { - schedule_download->timewindowstruct[i].maxretries = atoi(opaque); - } - t = mxmlWalkNext(t, b, MXML_DESCEND); - } - i++; - } - b = mxmlWalkNext(b, n, MXML_DESCEND); - } - if (!icwmp_validate_string_length(schedule_download->command_key, 32)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_string_length(schedule_download->url, 256)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_string_length(schedule_download->username, 256)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_string_length(schedule_download->password, 256)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_unsignedint(str_file_size)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - FREE(str_file_size); - goto fault; - } - FREE(str_file_size); - if (strcmp(file_type, FIRMWARE_UPGRADE_IMAGE_FILE_TYPE) && strcmp(file_type, WEB_CONTENT_FILE_TYPE) && strcmp(file_type, VENDOR_CONFIG_FILE_TYPE) && strcmp(file_type, TONE_FILE_TYPE) && strcmp(file_type, RINGER_FILE_TYPE) && strcmp(file_type, STORED_FIRMWARE_IMAGE_FILE_TYPE)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - } else if ((strcmp(windowmode0, "1 At Any Time") && strcmp(windowmode0, "2 Immediately") && strcmp(windowmode0, "3 When Idle")) || (strcmp(windowmode1, "1 At Any Time") && strcmp(windowmode1, "2 Immediately") && strcmp(windowmode1, "3 When Idle"))) { - error = FAULT_CPE_REQUEST_DENIED; - } else if (count_download_queue >= MAX_DOWNLOAD_QUEUE) { - error = FAULT_CPE_RESOURCES_EXCEEDED; - } else if (schedule_download->url == NULL || (strcmp(schedule_download->url, "") == 0)) { - error = FAULT_CPE_REQUEST_DENIED; - } else if (strstr(schedule_download->url, "@") != NULL) { - error = FAULT_CPE_INVALID_ARGUMENTS; - } else if (strncmp(schedule_download->url, DOWNLOAD_PROTOCOL_HTTP, strlen(DOWNLOAD_PROTOCOL_HTTP)) != 0 && strncmp(schedule_download->url, DOWNLOAD_PROTOCOL_FTP, strlen(DOWNLOAD_PROTOCOL_FTP)) != 0) { - error = FAULT_CPE_FILE_TRANSFER_UNSUPPORTED_PROTOCOL; - } else { - for (j = 0; j < 3; j++) { - if (schedule_download_delay[j] > schedule_download_delay[j + 1]) { - error = FAULT_CPE_INVALID_ARGUMENTS; - break; - } - } - } - - if (error != FAULT_CPE_NO_FAULT) - goto fault; - - t = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - if (!t) - goto fault; - - t = mxmlNewElement(t, "cwmp:ScheduleDownloadResponse"); // ScheduleDownloadResponse has no argument - if (!t) - goto fault; - - pthread_mutex_lock(&mutex_schedule_download); - list_add_tail(&(schedule_download->list), &(list_schedule_download)); - if (schedule_download_delay[0] != 0) { - count_download_queue++; - } - while (i > 0) { - i--; - schedule_download->timewindowstruct[i].windowstart = time(NULL) + schedule_download_delay[i * 2]; - schedule_download->timewindowstruct[i].windowend = time(NULL) + schedule_download_delay[i * 2 + 1]; - } - bkp_session_insert_schedule_download(schedule_download); - bkp_session_save(); - if (schedule_download_delay[0] != 0) { - CWMP_LOG(INFO, "Schedule download will start in %us", schedule_download_delay[0]); - } else { - CWMP_LOG(INFO, "Schedule Download will start at the end of session"); - } - pthread_mutex_unlock(&mutex_schedule_download); - pthread_cond_signal(&threshold_schedule_download); - - return 0; - -fault: - cwmp_free_schedule_download_request(schedule_download); - if (cwmp_create_fault_message(session, rpc, error)) - goto error; - return 0; - -error: - return -1; -} - -/* - * [RPC CPE]: Upload - */ -int cwmp_handle_rpc_cpe_upload(struct session *session, struct rpc *rpc) -{ - mxml_node_t *n, *b = session->body_in; - //char *file_type = NULL; - int error = FAULT_CPE_NO_FAULT; - struct upload *upload = NULL, *iupload; - struct list_head *ilist; - time_t scheduled_time = 0; - time_t upload_delay = 0; - char *str_upload_delay = NULL; - char c[256]; - - if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "Upload") == -1) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - - n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); - - if (!n) - return -1; - b = n; - - upload = calloc(1, sizeof(struct upload)); - if (upload == NULL) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - upload->f_instance = 0; - while (b != NULL) { - const char *node_opaque = mxmlGetOpaque(b); - mxml_node_t *parent = mxmlGetParent(b); - mxml_type_t node_type = mxmlGetType(b); - - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "CommandKey")) { - upload->command_key = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "FileType")) { - char log_config[16]={0}; - int ftype, instance = 0; - sscanf(node_opaque, "%1d Vendor %15s File %8d", &ftype, log_config, &instance); - if (strcmp(log_config, "Configuration") != 0 && strcmp(log_config, "Log") != 0) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } else if (strcmp(log_config, "Configuration") == 0 && ftype != 1 && ftype != 3) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } else if (strcmp(log_config, "Log") == 0 && ftype != 2 && ftype != 4) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if ((ftype == 3 || ftype == 4) && (instance == 0)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (ftype !=1 && ftype != 2 && ftype != 3 && ftype != 4) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - upload->file_type = strdup(node_opaque); - upload->f_instance = instance; - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "URL")) { - upload->url = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Username")) { - upload->username = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Password")) { - upload->password = strdup(node_opaque); - } - if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "DelaySeconds")) { - str_upload_delay = strdup(node_opaque); - upload_delay = atol(node_opaque); - } - b = mxmlWalkNext(b, n, MXML_DESCEND); - } - if (!icwmp_validate_string_length(upload->command_key, 32)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_string_length(upload->url, 256)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_string_length(upload->username, 256)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_string_length(upload->password, 256)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - goto fault; - } - if (!icwmp_validate_unsignedint(str_upload_delay)) { - error = FAULT_CPE_INVALID_ARGUMENTS; - FREE(str_upload_delay); - goto fault; - } - FREE(str_upload_delay); - - if (count_download_queue >= MAX_DOWNLOAD_QUEUE) { - error = FAULT_CPE_RESOURCES_EXCEEDED; - } else if (upload->url == NULL || (strcmp(upload->url, "") == 0)) { - error = FAULT_CPE_REQUEST_DENIED; - } else if (strstr(upload->url, "@") != NULL) { - error = FAULT_CPE_INVALID_ARGUMENTS; - } else if (strncmp(upload->url, DOWNLOAD_PROTOCOL_HTTPS, strlen(DOWNLOAD_PROTOCOL_HTTPS)) != 0 && strncmp(upload->url, DOWNLOAD_PROTOCOL_HTTP, strlen(DOWNLOAD_PROTOCOL_HTTP)) != 0 && strncmp(upload->url, DOWNLOAD_PROTOCOL_FTP, strlen(DOWNLOAD_PROTOCOL_FTP)) != 0) { - error = FAULT_CPE_FILE_TRANSFER_UNSUPPORTED_PROTOCOL; - } - - if (error != FAULT_CPE_NO_FAULT) { - goto fault; - } - - if (create_download_upload_response(session->tree_out, TYPE_UPLOAD) != FAULT_CPE_NO_FAULT) { - error = FAULT_CPE_INTERNAL_ERROR; - goto fault; - } - - if (error == FAULT_CPE_NO_FAULT) { - pthread_mutex_lock(&mutex_upload); - if (upload_delay != 0) - scheduled_time = time(NULL) + upload_delay + PROCESSING_DELAY; - - list_for_each (ilist, &(list_upload)) { - iupload = list_entry(ilist, struct upload, list); - if (iupload->scheduled_time >= scheduled_time) { - break; - } - } - list_add(&(upload->list), ilist->prev); - if (upload_delay != 0) { - count_download_queue++; - upload->scheduled_time = scheduled_time; - } - bkp_session_insert_upload(upload); - bkp_session_save(); - if (upload_delay != 0) { - CWMP_LOG(INFO, "Upload will start in %us", upload_delay); - } else { - CWMP_LOG(INFO, "Upload will start at the end of session"); - } - pthread_mutex_unlock(&mutex_upload); - pthread_cond_signal(&threshold_upload); - } - return 0; - -fault: - cwmp_free_upload_request(upload); - if (cwmp_create_fault_message(session, rpc, error)) - return -1; - return 0; -} - -/* - * [FAULT]: Fault - */ - -int cwmp_handle_rpc_cpe_fault(struct session *session, struct rpc *rpc) -{ - mxml_node_t *b, *t, *u, *body; - - body = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); - - b = mxmlNewElement(body, "soap_env:Fault"); - if (!b) - return -1; - - t = mxmlNewElement(b, "faultcode"); - if (!t) - return -1; - - u = mxmlNewOpaque(t, (FAULT_CPE_ARRAY[session->fault_code].TYPE == FAULT_CPE_TYPE_CLIENT) ? "Client" : "Server"); - if (!u) - return -1; - - t = mxmlNewElement(b, "faultstring"); - if (!t) - return -1; - - u = mxmlNewOpaque(t, "CWMP fault"); - if (!u) - return -1; - - b = mxmlNewElement(b, "detail"); - if (!b) - return -1; - - b = mxmlNewElement(b, "cwmp:Fault"); - if (!b) - return -1; - - t = mxmlNewElement(b, "FaultCode"); - if (!t) - return -1; - - u = mxmlNewOpaque(t, FAULT_CPE_ARRAY[session->fault_code].CODE); - if (!u) - return -1; - - t = mxmlNewElement(b, "FaultString"); - if (!b) - return -1; - - u = mxmlNewOpaque(t, FAULT_CPE_ARRAY[session->fault_code].DESCRIPTION); - if (!u) - return -1; - - if (rpc->type == RPC_CPE_SET_PARAMETER_VALUES) { - while (rpc->list_set_value_fault->next != rpc->list_set_value_fault) { - struct cwmp_param_fault *param_fault; - - param_fault = list_entry(rpc->list_set_value_fault->next, struct cwmp_param_fault, list); - - if (param_fault->fault) { - int idx; - idx = cwmp_get_fault_code(param_fault->fault); - - t = mxmlNewElement(b, "SetParameterValuesFault"); - if (!t) - return -1; - - u = mxmlNewElement(t, "ParameterName"); - if (!u) - return -1; - - u = mxmlNewOpaque(u, param_fault->name); - if (!u) - return -1; - - u = mxmlNewElement(t, "FaultCode"); - if (!u) - return -1; - - u = mxmlNewOpaque(u, FAULT_CPE_ARRAY[idx].CODE); - if (!u) - return -1; - - u = mxmlNewElement(t, "FaultString"); - if (!u) - return -1; - - u = mxmlNewOpaque(u, FAULT_CPE_ARRAY[idx].DESCRIPTION); - if (!u) - return -1; - } - cwmp_del_list_fault_param(param_fault); - } - } - - return 0; -} - -int cwmp_create_fault_message(struct session *session, struct rpc *rpc_cpe, int fault_code) -{ - CWMP_LOG(INFO, "Fault detected"); - session->fault_code = fault_code; - - MXML_DELETE(session->tree_out); - - if (xml_prepare_msg_out(session)) - return -1; - - CWMP_LOG(INFO, "Preparing the Fault message"); - if (rpc_cpe_methods[RPC_CPE_FAULT].handler(session, rpc_cpe)) - return -1; - rpc_cpe->type = RPC_CPE_FAULT; - - return 0; -} diff --git a/backupSession.c b/src/backupSession.c similarity index 98% rename from backupSession.c rename to src/backupSession.c index 758922d..ff7dc41 100644 --- a/backupSession.c +++ b/src/backupSession.c @@ -1,13 +1,14 @@ /* - * 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. + * backupSession.c - API to store/load CWMP session in/from backup XML files + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Mohamed Kallel * Author Ahmed Zribi * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #include @@ -521,7 +522,7 @@ void bkp_session_delete_apply_schedule_download(struct apply_schedule_download * void bkp_session_insert_change_du_state(struct change_du_state *pchange_du_state) { - struct operations *p; + struct operations *p = NULL; char schedule_time[128]; mxml_node_t *b, *n; @@ -662,7 +663,7 @@ void bkp_session_delete_upload(struct upload *pupload) 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]; - struct opresult *p; + struct opresult *p = NULL; mxml_node_t *b; pthread_mutex_lock(&mutex_backup_session); @@ -802,6 +803,10 @@ void load_queue_event(mxml_node_t *tree, struct cwmp *cwmp) const char *element = mxmlGetElement(b); if (strcmp(element, "command_key") == 0) { + // cppcheck-suppress knownConditionTrueFalse + /* + * idx value can be modified when loading the backup with the function load_specific_backup_attributes + */ if (idx != -1) { if (EVENT_CONST[idx].RETRY & EVENT_RETRY_AFTER_REBOOT) { event_container_save = cwmp_add_event_container(cwmp, idx, ((command_key != NULL) ? command_key : "")); diff --git a/inc/backupSession.h b/src/backupSession.h similarity index 88% rename from inc/backupSession.h rename to src/backupSession.h index b4e5b60..c55fb01 100644 --- a/inc/backupSession.h +++ b/src/backupSession.h @@ -1,19 +1,20 @@ /* - * 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. + * backupSession.h - API to store/load CWMP session in/from backup XML files + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2020 iopsys Software Solutions AB * Author Mohamed Kallel * Author Ahmed Zribi + * Author Omar Kallel + * + * See LICENSE file for license related information. * */ #ifndef _BACKUPSESSION_H__ #define _BACKUPSESSION_H__ -#include +#include "xml_utils.h" #include "common.h" #define RPC_NO_STATUS -1 diff --git a/common.c b/src/common.c similarity index 98% rename from common.c rename to src/common.c index 74df6ff..52f6473 100755 --- a/common.c +++ b/src/common.c @@ -1,12 +1,12 @@ /* - * 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. + * common.c - Some commun functions used by the application + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel * + * See LICENSE file for license related information. + * */ #include @@ -165,6 +165,7 @@ void add_dm_parameter_to_list(struct list_head *head, char *param_name, char *pa dm_parameter->value = strdup(param_val); dm_parameter->type = strdup(param_type ? param_type : "xsd:string"); + dm_parameter->access_list = strdup(""); dm_parameter->notification = notification; dm_parameter->writable = writable; } @@ -175,6 +176,7 @@ void delete_dm_parameter_from_list(struct cwmp_dm_parameter *dm_parameter) free(dm_parameter->name); free(dm_parameter->value); free(dm_parameter->type); + free(dm_parameter->access_list); free(dm_parameter); } diff --git a/inc/common.h b/src/common.h similarity index 97% rename from inc/common.h rename to src/common.h index 503d8ca..5ed900b 100644 --- a/inc/common.h +++ b/src/common.h @@ -1,13 +1,14 @@ /* - * 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. + * common.h - Some commun functions used by the application + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2020 iopsys Software Solutions AB * Author Omar Kallel * + * See LICENSE file for license related information. + * */ + #ifndef __CCOMMON_H #define __CCOMMON_H @@ -216,6 +217,7 @@ struct cwmp_dm_parameter { char *name; char *value; char *type; + char *access_list; int notification; bool writable; bool forced_notification_param; diff --git a/config.c b/src/config.c similarity index 98% rename from config.c rename to src/config.c index 0751795..08f0e38 100755 --- a/config.c +++ b/src/config.c @@ -1,14 +1,16 @@ /* - * 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. + * config.c - load/store icwmp application configuration + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Mohamed Kallel * Author Ahmed Zribi * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ + #include #include diff --git a/inc/config.h b/src/config.h similarity index 54% rename from inc/config.h rename to src/config.h index 41858bb..1336e4d 100755 --- a/inc/config.h +++ b/src/config.h @@ -1,13 +1,13 @@ /* - * 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. + * config.h - load/store icwmp application configuration * - * Copyright (C) 2013-2019 iopsys Software Solutions AB - * Author Mohamed Kallel + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Omar Kallel * Author Anis Ellouze * + * See LICENSE file for license related information. + * */ #ifndef _CONFIG_H__ diff --git a/cwmp.c b/src/cwmp.c similarity index 97% rename from cwmp.c rename to src/cwmp.c index c57464e..6dcdd05 100644 --- a/cwmp.c +++ b/src/cwmp.c @@ -1,13 +1,14 @@ /* - * 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. + * cwmp.c - icwmp Main file + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Mohamed Kallel * Author Ahmed Zribi * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #include @@ -28,7 +29,7 @@ #include "session.h" #include "diagnostic.h" #include "http.h" -#include "rpc_soap.h" +#include "rpc.h" #include "config.h" #include "backupSession.h" #include "ubus_utils.h" @@ -39,7 +40,6 @@ #include "datamodel_interface.h" #include "cwmp_du_state.h" #include "heartbeat.h" -#include "netlink.h" static pthread_t periodic_event_thread; static pthread_t scheduleInform_thread; @@ -230,7 +230,7 @@ int cwmp_schedule_rpc(struct cwmp *cwmp, struct session *session) struct list_head *ilist; struct rpc *rpc_acs, *rpc_cpe; - if (http_client_init(cwmp) || thread_end) { + if (icwmp_http_client_init(cwmp) || thread_end) { CWMP_LOG(INFO, "Initializing http client failed"); goto retry; } @@ -327,7 +327,7 @@ retry: end: MXML_DELETE(session->tree_in); MXML_DELETE(session->tree_out); - http_client_exit(); + icwmp_http_client_exit(); xml_exit(); return session->error; } @@ -571,16 +571,6 @@ static void *thread_uloop_run(void *v __attribute__((unused))) { 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; @@ -603,7 +593,7 @@ static void *thread_uloop_run(void *v __attribute__((unused))) static void *thread_http_cr_server_listen(void *v __attribute__((unused))) { - http_server_listen(); + icwmp_http_server_listen(); return NULL; } @@ -830,6 +820,7 @@ end: static int cwmp_init(struct cwmp *cwmp) { int error; + icwmp_init_list_services(); cwmp->event_id = 0; cwmp->cwmp_period = 0; @@ -1011,7 +1002,7 @@ int main(int argc, char **argv) return error; configure_var_state(&cwmp_main); - http_server_init(); + icwmp_http_server_init(); memset(&act, 0, sizeof(act)); act.sa_handler = icwmp_signal_handler; diff --git a/cwmp_cli.c b/src/cwmp_cli.c similarity index 95% rename from cwmp_cli.c rename to src/cwmp_cli.c index f566275..acb132e 100644 --- a/cwmp_cli.c +++ b/src/cwmp_cli.c @@ -1,11 +1,12 @@ /* - * 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. + * cwmp_cli.c - icwmp CLI + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #include @@ -64,7 +65,7 @@ void display_get_cmd_result(struct cmd_input in __attribute__((unused)), union c fprintf(stderr, "Fault %s: %s\n", fault, get_fault_message_by_fault_code(fault)); return; } - struct cwmp_dm_parameter *param_value; + struct cwmp_dm_parameter *param_value = NULL; list_for_each_entry (param_value, res.param_list, list) { fprintf(stdout, "%s => %s\n", param_value->name, param_value->value); } @@ -89,7 +90,7 @@ char *cmd_set_exec_func(struct cmd_input in, union cmd_result *res __attribute__ int fault_idx = cwmp_set_multiple_parameters_values(&list_set_param_value, "set_key", &flag, &faults_list); cwmp_free_all_dm_parameter_list(&list_set_param_value); if (fault_idx != FAULT_CPE_NO_FAULT) { - struct cwmp_param_fault *param_fault; + struct cwmp_param_fault *param_fault = NULL; char fault[5] = {0}; list_for_each_entry (param_fault, &faults_list, list) { snprintf(fault, sizeof(fault), "%d", param_fault->fault); @@ -204,7 +205,7 @@ void display_get_notif_cmd_result(struct cmd_input in __attribute__((unused)), u fprintf(stderr, "Fault %s: %s\n", fault, get_fault_message_by_fault_code(fault)); return; } - struct cwmp_dm_parameter *param_value; + struct cwmp_dm_parameter *param_value = NULL; list_for_each_entry (param_value, res.param_list, list) { fprintf(stdout, "%s => %s\n", param_value->name, param_value->notification == 2 ? "active" : param_value->notification == 1 ? "passive" : "off"); } @@ -266,7 +267,7 @@ void display_get_names_cmd_result(struct cmd_input in __attribute__((unused)), u fprintf(stderr, "Fault %s: %s\n", fault, get_fault_message_by_fault_code(fault)); return; } - struct cwmp_dm_parameter *param_value; + struct cwmp_dm_parameter *param_value = NULL; list_for_each_entry (param_value, res.param_list, list) { fprintf(stdout, "%s => %s\n", param_value->name, param_value->writable ? "writable" : "not-writable"); } diff --git a/inc/cwmp_cli.h b/src/cwmp_cli.h similarity index 79% rename from inc/cwmp_cli.h rename to src/cwmp_cli.h index d6fde40..8d2b4a9 100644 --- a/inc/cwmp_cli.h +++ b/src/cwmp_cli.h @@ -1,3 +1,14 @@ +/* + * cwmp_cli.h - icwmp CLI + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Omar Kallel + * + * See LICENSE file for license related information. + * + */ + #ifndef CWMP_CLI #define CWMP_CLI diff --git a/cwmp_du_state.c b/src/cwmp_du_state.c similarity index 97% rename from cwmp_du_state.c rename to src/cwmp_du_state.c index 914811a..99d71c9 100644 --- a/cwmp_du_state.c +++ b/src/cwmp_du_state.c @@ -1,11 +1,12 @@ /* - * 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. + * cwmp-du_state.c - ChangeDUState method corresponding functions + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #include @@ -156,7 +157,7 @@ static int get_deployment_unit_name_version(char *uuid, char **name, char **vers snprintf(name_param, sizeof(name_param), "Device.SoftwareModules.DeploymentUnit.%s.Name", sw_by_uuid_instance); snprintf(version_param, sizeof(version_param), "Device.SoftwareModules.DeploymentUnit.%s.Version", sw_by_uuid_instance); snprintf(environment_param, sizeof(environment_param), "Device.SoftwareModules.DeploymentUnit.%s.ExecutionEnvRef", sw_by_uuid_instance); - struct cwmp_dm_parameter *param_value; + struct cwmp_dm_parameter *param_value = NULL; list_for_each_entry (param_value, &sw_parameters, list) { if (strcmp(param_value->name, name_param) == 0) { *name = strdup(param_value->value); @@ -218,7 +219,7 @@ static char *get_exec_env_name(char *environment_path) if (err) return strdup(""); - struct cwmp_dm_parameter *param_value; + 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 (strcmp(param_value->name, env_param) == 0) { diff --git a/inc/cwmp_du_state.h b/src/cwmp_du_state.h similarity index 73% rename from inc/cwmp_du_state.h rename to src/cwmp_du_state.h index ed7c110..e356037 100644 --- a/inc/cwmp_du_state.h +++ b/src/cwmp_du_state.h @@ -1,11 +1,12 @@ /* - * 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. + * cwmp-du_state.h - ChangeDUState method corresponding functions + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #ifndef CWMP_DU_STATE_H diff --git a/cwmp_uci.c b/src/cwmp_uci.c similarity index 98% rename from cwmp_uci.c rename to src/cwmp_uci.c index ce77d75..fffd1b1 100644 --- a/cwmp_uci.c +++ b/src/cwmp_uci.c @@ -1,12 +1,14 @@ /* - * 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. + * cwmp_uci.c - API to manage UCI packages/sections/options + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ + #include #include #include diff --git a/inc/cwmp_uci.h b/src/cwmp_uci.h similarity index 95% rename from inc/cwmp_uci.h rename to src/cwmp_uci.h index 39d1b63..3b84c52 100644 --- a/inc/cwmp_uci.h +++ b/src/cwmp_uci.h @@ -1,14 +1,15 @@ /* - * 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. + * cwmp_uci.h - API to manage UCI packages/sections/options + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2020 iopsys Software Solutions AB * Author Omar Kallel * + * See LICENSE file for license related information. + * */ + #ifndef __CWMPUCI_H #define __CWMPUCI_H diff --git a/cwmp_zlib.c b/src/cwmp_zlib.c similarity index 84% rename from cwmp_zlib.c rename to src/cwmp_zlib.c index 7495fa5..bb0a9bd 100644 --- a/cwmp_zlib.c +++ b/src/cwmp_zlib.c @@ -1,11 +1,12 @@ /* - * 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. + * cwmp_zlib.c - ZLIB compresssion of CWMP messages + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Mohamed Kallel + * + * See LICENSE file for license related information. * - * Copyright (C) 2014-2021 iopsys Software Solutions AB - * Author Mohamed Kallel */ #include diff --git a/src/cwmp_zlib.h b/src/cwmp_zlib.h new file mode 100644 index 0000000..5f94b30 --- /dev/null +++ b/src/cwmp_zlib.h @@ -0,0 +1,17 @@ +/* + * cwmp_zlib.h - ZLIB compresssion of CWMP messages + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Mohamed Kallel + * + * See LICENSE file for license related information. + * + */ + +#ifndef __ZLIB_H +#define __ZLIB_H + +int zlib_compress(char *message, unsigned char **zmsg, int *zlen, int type); + +#endif diff --git a/datamodel_interface.c b/src/datamodel_interface.c similarity index 98% rename from datamodel_interface.c rename to src/datamodel_interface.c index 304d4e2..bb11cba 100755 --- a/datamodel_interface.c +++ b/src/datamodel_interface.c @@ -1,11 +1,12 @@ /* - * 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. + * datamodel_interface.c - API to call BBF datamodel functions (set, get, add, delete, setattributes, getattributes, getnames, ...) + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #include @@ -440,7 +441,7 @@ 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 cwmp_dm_parameter *param_value = NULL; struct list_params_result get_result = { .parameters_list = parameters_list }; struct blob_buf b = { 0 }; @@ -536,7 +537,7 @@ 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 cwmp_dm_parameter *param_value = NULL; struct setm_values_res set_result = { .flag = flag, .faults_list = faults_list }; struct cwmp *cwmp = &cwmp_main; struct blob_buf b = { 0 }; diff --git a/inc/datamodel_interface.h b/src/datamodel_interface.h similarity index 78% rename from inc/datamodel_interface.h rename to src/datamodel_interface.h index 6d76b6e..278123a 100644 --- a/inc/datamodel_interface.h +++ b/src/datamodel_interface.h @@ -1,3 +1,14 @@ +/* + * datamodel_interface.h - API to call BBF datamodel functions (set, get, add, delete, setattributes, getattributes, getnames, ...) + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Omar Kallel + * + * See LICENSE file for license related information. + * + */ + #ifndef SRC_DATAMODELIFACE_H_ #define SRC_DATAMODELIFACE_H_ diff --git a/diagnostic.c b/src/diagnostic.c similarity index 97% rename from diagnostic.c rename to src/diagnostic.c index eba05e3..5f119d6 100644 --- a/diagnostic.c +++ b/src/diagnostic.c @@ -1,14 +1,16 @@ /* - * 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. + * diagnostic.c - Manage Diagnostics parameters from icwmp + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2021 iopsys Software Solutions AB * Author Imen Bhiri * Author: Amin Ben Ramdhane * Author: Omar Kallel + * + * See LICENSE file for license related information. + * */ + #include #include "common.h" diff --git a/src/diagnostic.h b/src/diagnostic.h new file mode 100644 index 0000000..0430f4c --- /dev/null +++ b/src/diagnostic.h @@ -0,0 +1,27 @@ +/* + * diagnostic.h - Manage Diagnostics parameters from icwmp + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Imen Bhiri + * Author: Amin Ben Ramdhane + * Author: Omar Kallel + * + * See LICENSE file for license related information. + * + */ + +#ifndef __DIAGNOSTIC__H +#define __DIAGNOSTIC__H + +bool set_diagnostic_parameter_structure_value(char *parameter_name, char *value); + +int cwmp_download_diagnostics(); +int cwmp_upload_diagnostics(); +int cwmp_ip_ping_diagnostics(); +int cwmp_nslookup_diagnostics(); +int cwmp_traceroute_diagnostics(); +int cwmp_udp_echo_diagnostics(); +int cwmp_serverselection_diagnostics(); + +#endif diff --git a/digauth.c b/src/digauth.c similarity index 98% rename from digauth.c rename to src/digauth.c index d12fa75..01faa6a 100644 --- a/digauth.c +++ b/src/digauth.c @@ -144,10 +144,10 @@ static void get_hexstring(unsigned const char *hash, int len, char *hexstr, int static void get_value_from_header(const char *data) { - if (data == NULL) + if (CWMP_STRLEN(data) == 0) return; - int header_len = strlen(data) + 1; + int header_len = CWMP_STRLEN(data) + 1; char header[header_len]; memset(header, 0, header_len); strncpy(header, data, header_len); @@ -167,7 +167,7 @@ static void get_value_from_header(const char *data) strip_lead_trail_char(key, '\"'); eq = eq + 1; - char *end = eq + strlen(eq) - 1; + char *end = eq + CWMP_STRLEN(eq) - 1; len = end - eq + 2; char val[len]; snprintf(val, len, "%s", eq); diff --git a/inc/digauth.h b/src/digauth.h similarity index 67% rename from inc/digauth.h rename to src/digauth.h index 6846a27..3f74ab4 100644 --- a/inc/digauth.h +++ b/src/digauth.h @@ -1,3 +1,13 @@ +/* + * digauth.h - HTTP digest authentication utility + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author: suvendhu.hansa@iopsys.eu + * + * See LICENSE file for license related information. + * + */ #ifndef DIGAUTH_H_ #define DIGAUTH_H_ diff --git a/download.c b/src/download.c similarity index 98% rename from download.c rename to src/download.c index 704551f..3954d42 100644 --- a/download.c +++ b/src/download.c @@ -1,13 +1,13 @@ /* - * 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. + * download.c - Download method functions + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author: Omar Kallel + * + * See LICENSE file for license related information. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB - * Author Omar Kallel */ - #include #include #include diff --git a/inc/download.h b/src/download.h similarity index 89% rename from inc/download.h rename to src/download.h index 241b66e..34a09c1 100644 --- a/inc/download.h +++ b/src/download.h @@ -1,3 +1,13 @@ +/* + * download.h - Download method functions + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author: Omar Kallel + * + * See LICENSE file for license related information. + * + */ #ifndef CWMP_DOWNLOAD_H #define CWMP_DOWNLOAD_H diff --git a/event.c b/src/event.c similarity index 98% rename from event.c rename to src/event.c index 3b1216b..7891746 100644 --- a/event.c +++ b/src/event.c @@ -1,14 +1,14 @@ /* - * 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. + * event.c - Manage CWMP Events + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Mohamed Kallel * Author Ahmed Zribi * Author Omar Kallel * + * See LICENSE file for license related information. + * */ #include "backupSession.h" @@ -389,7 +389,7 @@ void *thread_event_periodic(void *v) bool event_exist_in_list(struct cwmp *cwmp, int event) { - struct event_container *event_container; + struct event_container *event_container = NULL; list_for_each_entry (event_container, cwmp->head_event_container, list) { if (event_container->code == event) return true; diff --git a/inc/event.h b/src/event.h similarity index 87% rename from inc/event.h rename to src/event.h index 8803d6e..7c57085 100644 --- a/inc/event.h +++ b/src/event.h @@ -1,12 +1,12 @@ /* - * 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. + * event.h - Manage CWMP Events + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2020 iopsys Software Solutions AB * Author Omar Kallel * + * See LICENSE file for license related information. + * */ #ifndef EVENT_H_ diff --git a/heartbeat.c b/src/heartbeat.c similarity index 96% rename from heartbeat.c rename to src/heartbeat.c index d831acd..401c131 100644 --- a/heartbeat.c +++ b/src/heartbeat.c @@ -1,3 +1,13 @@ +/* + * heartbeat.c - CWMP HeartBeat mechanism + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author Omar Kallel + * + * See LICENSE file for license related information. + * + */ #include #include diff --git a/inc/heartbeat.h b/src/heartbeat.h similarity index 65% rename from inc/heartbeat.h rename to src/heartbeat.h index cde6978..9102dce 100644 --- a/inc/heartbeat.h +++ b/src/heartbeat.h @@ -1,3 +1,13 @@ +/* + * heartbeat.h - CWMP HeartBeat mechanism + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author Omar Kallel + * + * See LICENSE file for license related information. + * + */ #ifndef HEARTBEAT_H #define HEARTBEAT_H diff --git a/http.c b/src/http.c similarity index 92% rename from http.c rename to src/http.c index 97944f2..e51b307 100644 --- a/http.c +++ b/src/http.c @@ -1,14 +1,14 @@ /* - * 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. + * http.c - API for HTTP exchanges + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB - * Author Mohamed Kallel - * Author Ahmed Zribi * Author Omar Kallel - * Copyright (C) 2011-2012 Luka Perkov + * Author Mohamed Kallel + * Author Ahmed Zribi + * + * See LICENSE file for license related information. + * */ #include #include @@ -39,7 +39,7 @@ void http_set_timeout(void) curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1); } -int http_client_init(struct cwmp *cwmp) +int icwmp_http_client_init(struct cwmp *cwmp) { char *dhcp_dis = NULL; char *acs_var_stat = NULL; @@ -96,7 +96,7 @@ int http_client_init(struct cwmp *cwmp) return 0; } -void http_client_exit(void) +void icwmp_http_client_exit(void) { icwmp_free(http_c.url); @@ -131,7 +131,69 @@ static size_t http_get_response(void *buffer, size_t size, size_t rxed, char **m return size * rxed; } -int http_send_message(struct cwmp *cwmp, char *msg_out, int msg_out_len, char **msg_in) +static void http_set_security_options(struct cwmp *cwmp) +{ + curl_easy_setopt(curl, CURLOPT_USERNAME, cwmp->conf.acs_userid); + curl_easy_setopt(curl, CURLOPT_PASSWORD, cwmp->conf.acs_passwd); + curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC | CURLAUTH_DIGEST); + + if (cwmp->conf.acs_ssl_capath) + curl_easy_setopt(curl, CURLOPT_CAPATH, cwmp->conf.acs_ssl_capath); + if (cwmp->conf.insecure_enable) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + } +} + +static void http_set_connection_options(struct cwmp *cwmp) +{ + curl_easy_setopt(curl, CURLOPT_URL, http_c.url); + + curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_TIMEOUT); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, HTTP_TIMEOUT); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); + curl_easy_setopt(curl, CURLOPT_NOBODY, 0); +#ifdef DEVEL + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); +#endif + + curl_easy_setopt(curl, CURLOPT_COOKIEFILE, fc_cookies); + curl_easy_setopt(curl, CURLOPT_COOKIEJAR, fc_cookies); + + curl_easy_setopt(curl, CURLOPT_INTERFACE, cwmp->conf.interface); +} + +static void http_set_header_list_options(struct cwmp *cwmp) +{ + switch (cwmp->conf.compression) { + case COMP_NONE: + break; + case COMP_GZIP: + curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip"); + http_c.header_list = curl_slist_append(http_c.header_list, "Content-Encoding: gzip"); + break; + case COMP_DEFLATE: + curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate"); + http_c.header_list = curl_slist_append(http_c.header_list, "Content-Encoding: deflate"); + break; + } + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_c.header_list); +} + +static void http_set_inout_options(char *msg_out, int msg_out_len, char **msg_in) +{ + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg_out); + if (msg_out) + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)msg_out_len); + else + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_response); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, msg_in); +} + +int icwmp_http_send_message(struct cwmp *cwmp, char *msg_out, int msg_out_len, char **msg_in) { unsigned char buf[sizeof(struct in6_addr)]; int tmp = 0; @@ -158,53 +220,13 @@ int http_send_message(struct cwmp *cwmp, char *msg_out, int msg_out_len, char ** if (!http_c.header_list) return -1; } - curl_easy_setopt(curl, CURLOPT_URL, http_c.url); - curl_easy_setopt(curl, CURLOPT_USERNAME, cwmp->conf.acs_userid); - curl_easy_setopt(curl, CURLOPT_PASSWORD, cwmp->conf.acs_passwd); - curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC | CURLAUTH_DIGEST); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_TIMEOUT); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, HTTP_TIMEOUT); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); - curl_easy_setopt(curl, CURLOPT_NOBODY, 0); - switch (cwmp->conf.compression) { - case COMP_NONE: - break; - case COMP_GZIP: - curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip"); - http_c.header_list = curl_slist_append(http_c.header_list, "Content-Encoding: gzip"); - break; - case COMP_DEFLATE: - curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate"); - http_c.header_list = curl_slist_append(http_c.header_list, "Content-Encoding: deflate"); - break; - } - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_c.header_list); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg_out); - if (msg_out) - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)msg_out_len); - else - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0); + http_set_connection_options(cwmp); + http_set_security_options(cwmp); + http_set_header_list_options(cwmp); + http_set_inout_options(msg_out, msg_out_len, msg_in); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_response); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, msg_in); - -#ifdef DEVEL - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); -#endif curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); - curl_easy_setopt(curl, CURLOPT_COOKIEFILE, fc_cookies); - curl_easy_setopt(curl, CURLOPT_COOKIEJAR, fc_cookies); - - if (cwmp->conf.acs_ssl_capath) - curl_easy_setopt(curl, CURLOPT_CAPATH, cwmp->conf.acs_ssl_capath); - if (cwmp->conf.insecure_enable) { - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); - } - - curl_easy_setopt(curl, CURLOPT_INTERFACE, cwmp->conf.interface); *msg_in = (char *)calloc(1, sizeof(char)); res = curl_easy_perform(curl); @@ -279,7 +301,7 @@ error: return -1; } -void http_success_cr(void) +static void http_success_cr(void) { CWMP_LOG(INFO, "Connection Request thread: add connection request event in the queue"); pthread_mutex_lock(&(cwmp_main.mutex_session_queue)); @@ -291,14 +313,14 @@ void http_success_cr(void) static void http_cr_new_client(int client, bool service_available) { FILE *fp; - char buffer[BUFSIZ]; - char auth_digest_buffer[BUFSIZ]; + char buffer[BUFSIZ] = {0}; + char auth_digest_buffer[BUFSIZ] = {0}; int8_t auth_status = 0; bool auth_digest_checked = false; bool method_is_get = false; bool internal_error = false; - char cr_http_get_head[HTTP_GET_HDR_LEN]; + char cr_http_get_head[HTTP_GET_HDR_LEN] = {0}; pthread_mutex_lock(&mutex_config_load); fp = fdopen(client, "r+"); @@ -388,7 +410,7 @@ http_end: pthread_mutex_unlock(&mutex_config_load); } -void http_server_init(void) +void icwmp_http_server_init(void) { struct sockaddr_in6 server = { 0 }; unsigned short cr_port; @@ -438,7 +460,7 @@ void http_server_init(void) CWMP_LOG(INFO, "Connection Request server initiated with the port: %d", cr_port); } -void http_server_listen(void) +void icwmp_http_server_listen(void) { int client_sock, c; int cr_request = 0; diff --git a/src/http.h b/src/http.h new file mode 100644 index 0000000..a6fb776 --- /dev/null +++ b/src/http.h @@ -0,0 +1,36 @@ +/* + * http.h - API for HTTP exchanges + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author Omar Kallel + * Author Mohamed Kallel + * Author Ahmed Zribi + * + * See LICENSE file for license related information. + * + */ +#ifndef _FREECWMP_HTTP_H__ +#define _FREECWMP_HTTP_H__ + +#include "common.h" + +extern char *fc_cookies; + +#define HTTP_TIMEOUT 60 + +struct http_client { + struct curl_slist *header_list; + char *url; +}; + +void http_set_timeout(void); + +int icwmp_http_client_init(struct cwmp *cwmp); +void icwmp_http_client_exit(void); +int icwmp_http_send_message(struct cwmp *cwmp, char *msg_out, int msg_out_len, char **msg_in); + +void icwmp_http_server_init(void); +void icwmp_http_server_listen(void); + +#endif diff --git a/log.c b/src/log.c similarity index 93% rename from log.c rename to src/log.c index 7a0f1e1..2a1620e 100644 --- a/log.c +++ b/src/log.c @@ -1,12 +1,13 @@ /* - * 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. + * log.c - CWMP Logs functions * - * Copyright (C) 2013-2021 iopsys Software Solutions AB - * Author Mohamed Kallel + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author Mohamed Kallel * Author Ahmed Zribi + * Author Omar Kallel + * + * See LICENSE file for license related information. * */ diff --git a/inc/log.h b/src/log.h similarity index 69% rename from inc/log.h rename to src/log.h index 5cb7ba5..f9a4eb2 100644 --- a/inc/log.h +++ b/src/log.h @@ -1,12 +1,13 @@ /* - * 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. + * log.h - CWMP Logs functions * - * Copyright (C) 2013-2019 iopsys Software Solutions AB - * Author Mohamed Kallel + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author Mohamed Kallel * Author Ahmed Zribi + * Author Omar Kallel + * + * See LICENSE file for license related information. * */ diff --git a/notifications.c b/src/notifications.c similarity index 97% rename from notifications.c rename to src/notifications.c index 04bcb58..186fffc 100644 --- a/notifications.c +++ b/src/notifications.c @@ -1,12 +1,12 @@ /* - * 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. + * notifications.c - Manage CWMP Notifications + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel * + * See LICENSE file for license related information. + * */ #include @@ -207,7 +207,7 @@ int get_parameter_leaf_notification_from_childs_list(char *parameter_name, struc { char *parent = NULL; int ret_notif = -1; - struct cwmp_dm_parameter *param_value; + struct cwmp_dm_parameter *param_value = NULL; if (childs_list == NULL) return -1; list_for_each_entry (param_value, childs_list, list) { @@ -239,7 +239,7 @@ char *cwmp_get_parameter_attributes(char *parameter_name, struct list_head *para cwmp_free_all_dm_parameter_list(&childs_notifs); return error; } - struct cwmp_dm_parameter *param_value; + struct cwmp_dm_parameter *param_value = NULL; list_for_each_entry (param_value, ¶ms_list, list) { int notif_leaf; notif_leaf = check_parameter_forced_notification(param_value->name); @@ -307,7 +307,7 @@ void create_list_param_obj_notify() char* updated_list_param_leaf_notify_with_sub_parameter_list(struct list_head *list_param_leaf_notify, struct cwmp_dm_parameter parent_parameter, void (*update_notify_file_line_arg)(FILE *notify_file, char *param_name, char *param_type, char *param_value, int notification), FILE* notify_file_arg) { - struct cwmp_dm_parameter *param_iter; + struct cwmp_dm_parameter *param_iter = NULL; LIST_HEAD(params_list); char *err = cwmp_get_parameter_values(parent_parameter.name, ¶ms_list); if (err) @@ -326,7 +326,7 @@ char* updated_list_param_leaf_notify_with_sub_parameter_list(struct list_head *l void create_list_param_leaf_notify(struct list_head *list_param_leaf_notify, void (*update_notify_file_line_arg)(FILE *notify_file, char *param_name, char *param_type, char *param_value, int notification), FILE* notify_file_arg) { - struct cwmp_dm_parameter *param_iter; + struct cwmp_dm_parameter *param_iter = NULL; int i; for (i = 0; i < (int)ARRAY_SIZE(forced_notifications_parameters); i++) @@ -462,7 +462,7 @@ void load_custom_notify_json(struct cwmp *cwmp) */ void get_parameter_value_from_parameters_list(struct list_head *params_list, char *parameter_name, char **value, char **type) { - struct cwmp_dm_parameter *param_value; + struct cwmp_dm_parameter *param_value = NULL; list_for_each_entry (param_value, params_list, list) { if (param_value->name == NULL) continue; diff --git a/inc/notifications.h b/src/notifications.h similarity index 88% rename from inc/notifications.h rename to src/notifications.h index b0415c1..ccbaa38 100644 --- a/inc/notifications.h +++ b/src/notifications.h @@ -1,12 +1,12 @@ /* - * 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. + * notifications.h - Manage CWMP Notifications + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2020 iopsys Software Solutions AB * Author Omar Kallel * + * See LICENSE file for license related information. + * */ #ifndef NOTIFICATIONS_H_ diff --git a/reboot.c b/src/reboot.c similarity index 92% rename from reboot.c rename to src/reboot.c index 837fd82..c0d600f 100644 --- a/reboot.c +++ b/src/reboot.c @@ -1,11 +1,12 @@ /* - * 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. + * reboot.c - Reboot method fuctions + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2021 iopsys Software Solutions AB * Author Amin Ben Ramdhane + * + * See LICENSE file for license related information. + * */ #include diff --git a/src/reboot.h b/src/reboot.h new file mode 100644 index 0000000..98b2992 --- /dev/null +++ b/src/reboot.h @@ -0,0 +1,20 @@ +/* + * reboot.h - Reboot method fuctions + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author Amin Ben Ramdhane + * + * See LICENSE file for license related information. + * + */ + +#ifndef _REBOOT_H__ +#define _REBOOT_H__ + +#include "common.h" + +void launch_reboot_methods(struct cwmp *cwmp); + +#endif //_REBOOT_H__ + diff --git a/src/rpc.c b/src/rpc.c new file mode 100755 index 0000000..bc1577b --- /dev/null +++ b/src/rpc.c @@ -0,0 +1,1960 @@ +/* + * rpc.c - CWMP RPC methods + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Mohamed Kallel + * Author Ahmed Zribi + * Author Omar Kallel + * + * See LICENSE file for license related information. + * + */ + +#include "rpc.h" + +#include "download.h" +#include "cwmp_du_state.h" +#include "log.h" +#include "event.h" +#include "datamodel_interface.h" +#include "event.h" +#include "xml.h" +#include "backupSession.h" +#include "notifications.h" +#include "upload.h" +#include "sched_inform.h" +#include "diagnostic.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 +#define DM_CONN_REQ_URL "Device.ManagementServer.ConnectionRequestURL" + +struct cwmp_namespaces ns; +const struct rpc_cpe_method rpc_cpe_methods[] = { [RPC_CPE_GET_RPC_METHODS] = { "GetRPCMethods", cwmp_handle_rpc_cpe_get_rpc_methods, AMD_1 }, + [RPC_CPE_SET_PARAMETER_VALUES] = { "SetParameterValues", cwmp_handle_rpc_cpe_set_parameter_values, AMD_1 }, + [RPC_CPE_GET_PARAMETER_VALUES] = { "GetParameterValues", cwmp_handle_rpc_cpe_get_parameter_values, AMD_1 }, + [RPC_CPE_GET_PARAMETER_NAMES] = { "GetParameterNames", cwmp_handle_rpc_cpe_get_parameter_names, AMD_1 }, + [RPC_CPE_SET_PARAMETER_ATTRIBUTES] = { "SetParameterAttributes", cwmp_handle_rpc_cpe_set_parameter_attributes, AMD_1 }, + [RPC_CPE_GET_PARAMETER_ATTRIBUTES] = { "GetParameterAttributes", cwmp_handle_rpc_cpe_get_parameter_attributes, AMD_1 }, + [RPC_CPE_ADD_OBJECT] = { "AddObject", cwmp_handle_rpc_cpe_add_object, AMD_1 }, + [RPC_CPE_DELETE_OBJECT] = { "DeleteObject", cwmp_handle_rpc_cpe_delete_object, AMD_1 }, + [RPC_CPE_REBOOT] = { "Reboot", cwmp_handle_rpc_cpe_reboot, AMD_1 }, + [RPC_CPE_DOWNLOAD] = { "Download", cwmp_handle_rpc_cpe_download, AMD_1 }, + [RPC_CPE_UPLOAD] = { "Upload", cwmp_handle_rpc_cpe_upload, AMD_1 }, + [RPC_CPE_FACTORY_RESET] = { "FactoryReset", cwmp_handle_rpc_cpe_factory_reset, AMD_1 }, + [RPC_CPE_CANCEL_TRANSFER] = { "CancelTransfer", cwmp_handle_rpc_cpe_cancel_transfer, AMD_3 }, + [RPC_CPE_SCHEDULE_INFORM] = { "ScheduleInform", cwmp_handle_rpc_cpe_schedule_inform, AMD_1 }, + [RPC_CPE_SCHEDULE_DOWNLOAD] = { "ScheduleDownload", cwmp_handle_rpc_cpe_schedule_download, AMD_3 }, + [RPC_CPE_CHANGE_DU_STATE] = { "ChangeDUState", cwmp_handle_rpc_cpe_change_du_state, AMD_3 }, + [RPC_CPE_X_FACTORY_RESET_SOFT] = { "X_FactoryResetSoft", cwmp_handle_rpc_cpe_x_factory_reset_soft, AMD_1 }, + [RPC_CPE_FAULT] = { "Fault", cwmp_handle_rpc_cpe_fault, AMD_1 } }; + +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 } +}; + +char *custom_forced_inform_parameters[MAX_NBRE_CUSTOM_INFORM] = { 0 }; +char *boot_inform_parameters[MAX_NBRE_CUSTOM_INFORM] = { 0 }; +int nbre_custom_inform = 0; +int nbre_boot_inform = 0; +char *forced_inform_parameters[] = { + "Device.RootDataModelVersion", + "Device.DeviceInfo.HardwareVersion", + "Device.DeviceInfo.SoftwareVersion", + "Device.DeviceInfo.ProvisioningCode", + "Device.ManagementServer.ParameterKey", + DM_CONN_REQ_URL, + "Device.ManagementServer.AliasBasedAddressing" +}; + +int xml_handle_message(struct session *session) +{ + struct rpc *rpc_cpe; + char *c; + int i; + mxml_node_t *b; + struct cwmp *cwmp = &cwmp_main; + struct config *conf; + conf = &(cwmp->conf); + + /* get method */ + if (icwmp_asprintf(&c, "%s:%s", ns.soap_env, "Body") == -1) { + CWMP_LOG(INFO, "Internal error"); + session->fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + b = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); + + if (!b) { + CWMP_LOG(INFO, "Invalid received message"); + session->fault_code = FAULT_CPE_REQUEST_DENIED; + goto fault; + } + session->body_in = b; + + while (1) { + b = mxmlWalkNext(b, session->body_in, MXML_DESCEND_FIRST); + if (!b) + goto error; + if (mxmlGetType(b) == MXML_ELEMENT) + break; + } + + c = (char *)mxmlGetElement(b); + /* convert QName to localPart, check that ns is the expected one */ + if (strchr(c, ':')) { + char *tmp = strchr(c, ':'); + size_t ns_len = tmp - c; + + if (strlen(ns.cwmp) != ns_len) { + CWMP_LOG(INFO, "Invalid received message"); + session->fault_code = FAULT_CPE_REQUEST_DENIED; + goto fault; + } + + if (strncmp(ns.cwmp, c, ns_len)) { + CWMP_LOG(INFO, "Invalid received message"); + session->fault_code = FAULT_CPE_REQUEST_DENIED; + goto fault; + } + + c = tmp + 1; + } else { + CWMP_LOG(INFO, "Invalid received message"); + session->fault_code = FAULT_CPE_REQUEST_DENIED; + goto fault; + } + CWMP_LOG(INFO, "SOAP RPC message: %s", c); + rpc_cpe = NULL; + for (i = 1; i < __RPC_CPE_MAX; i++) { + if (i != RPC_CPE_FAULT && strcmp(c, rpc_cpe_methods[i].name) == 0 && rpc_cpe_methods[i].amd <= conf->supported_amd_version) { + CWMP_LOG(INFO, "%s RPC is supported", c); + rpc_cpe = cwmp_add_session_rpc_cpe(session, i); + if (rpc_cpe == NULL) + goto error; + break; + } + } + if (!rpc_cpe) { + CWMP_LOG(INFO, "%s RPC is not supported", c); + session->fault_code = FAULT_CPE_METHOD_NOT_SUPPORTED; + goto fault; + } + return 0; +fault: + rpc_cpe = cwmp_add_session_rpc_cpe(session, RPC_CPE_FAULT); + if (rpc_cpe == NULL) + goto error; + return 0; +error: + return -1; +} + +/* + * [RPC ACS]: Inform + */ +static int xml_prepare_parameters_inform(struct cwmp_dm_parameter *dm_parameter, mxml_node_t *parameter_list, int *size) +{ + mxml_node_t *node = NULL, *b; + b = mxmlFindElementOpaque(parameter_list, parameter_list, dm_parameter->name, MXML_DESCEND); + if (b && dm_parameter->value != NULL) { + node = mxmlGetParent(b); + b = mxmlFindElement(node, node, "Value", NULL, NULL, MXML_DESCEND_FIRST); + if (!b) + return 0; + mxml_node_t *c = mxmlGetFirstChild(b); + if (c && strcmp(dm_parameter->value, mxmlGetOpaque(c)) == 0) + return 0; + mxmlDelete(b); + (*size)--; + } else if (dm_parameter->value == NULL) + return 0; + + char *type = (dm_parameter->type && dm_parameter->type[0] != '\0') ? dm_parameter->type : "xsd:string"; + if (node == NULL) { + struct xml_data_struct inform_params_xml_attrs = {0}; + struct xml_list_data *xml_data = calloc(1, sizeof(struct xml_list_data)); + xml_data->param_name = strdup(dm_parameter->name); + xml_data->param_value = strdup(dm_parameter->value); + xml_data->param_type = strdup(type); + LIST_HEAD(prameters_xml_list); + list_add_tail(&xml_data->list, &prameters_xml_list); + inform_params_xml_attrs.data_list = &prameters_xml_list; + int fault = build_xml_node_data(SOAP_PARAM_STRUCT, parameter_list, &inform_params_xml_attrs); + if (fault != CWMP_OK) + return -1; + + cwmp_free_all_xml_data_list(&prameters_xml_list); + } else { + struct xml_data_struct inform_param_value_xml_attrs = {0}; + inform_param_value_xml_attrs.value = &dm_parameter->value; + inform_param_value_xml_attrs.xsi_type = &type; + + int fault = build_xml_node_data(SOAP_VALUE_STRUCT, node, &inform_param_value_xml_attrs); + if (fault != CWMP_OK) + return -1; + } + + (*size)++; + return 0; +} + +static void load_inform_xml_schema(mxml_node_t **tree, struct cwmp *cwmp, struct session *session) +{ + char declaration[1024] = {0}; + mxml_node_t *xml = NULL, *envelope = NULL; + if (tree == NULL) + return; + + *tree = NULL; + + snprintf(declaration, sizeof(declaration), "?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?"); + + xml= mxmlNewElement(NULL, declaration); + if (xml == NULL) + return; + + struct xml_data_struct env_xml_attrs = {0}; + + env_xml_attrs.xml_env = &envelope; + env_xml_attrs.amd_version = &cwmp->conf.supported_amd_version; + env_xml_attrs.session_timeout = &cwmp->conf.session_timeout; + + int fault = build_xml_node_data(SOAP_ENV, xml, &env_xml_attrs); + + if (envelope == NULL || fault != CWMP_OK) { + MXML_DELETE(xml); + return; + } + + mxml_node_t *inform = build_top_body_soap_request(envelope, "Inform"); + if (inform == NULL) { + MXML_DELETE(xml); + return; + } + + struct xml_data_struct inform_xml_attrs = {0}; + + char *manufacturer = cwmp->deviceid.manufacturer ? cwmp->deviceid.manufacturer : ""; + char *oui = cwmp->deviceid.oui ? cwmp->deviceid.oui : ""; + char *product_class = cwmp->deviceid.productclass ? cwmp->deviceid.productclass : ""; + char *serial_number = cwmp->deviceid.serialnumber ? cwmp->deviceid.serialnumber : ""; + int max_env = 1; + char *current_time = get_time(time(NULL)); + + inform_xml_attrs.manufacturer = &manufacturer; + inform_xml_attrs.oui = &oui; + inform_xml_attrs.product_class = &product_class; + inform_xml_attrs.serial_number = &serial_number; + inform_xml_attrs.max_envelopes = &max_env; + inform_xml_attrs.current_time = ¤t_time; + inform_xml_attrs.retry_count = &cwmp->retry_count_session; + + LIST_HEAD(xml_events_list); + event_container_list_to_xml_data_list(&(session->head_event_container), &xml_events_list); + inform_xml_attrs.data_list = &xml_events_list; + + fault = build_xml_node_data(SOAP_INFORM_CWMP, inform, &inform_xml_attrs); + if (fault != CWMP_OK) { + MXML_DELETE(xml); + return; + } + + cwmp_free_all_xml_data_list(&xml_events_list); + mxml_node_t *param_list = mxmlNewElement(inform, "ParameterList"); + if (param_list == NULL) { + MXML_DELETE(xml); + return; + } + + mxmlElementSetAttr(param_list, "soap_enc:arrayType", "cwmp:ParameterValueStruct[0]"); + + struct list_head *ilist, *jlist; + struct cwmp_dm_parameter *dm_parameter; + int size = 0; + + list_for_each (ilist, &(session->head_event_container)) { + struct event_container *event_container = list_entry(ilist, struct event_container, list); + list_for_each (jlist, &(event_container->head_dm_parameter)) { + dm_parameter = list_entry(jlist, struct cwmp_dm_parameter, list); + if (xml_prepare_parameters_inform(dm_parameter, param_list, &size)) { + MXML_DELETE(xml); + return; + } + } + } + + size_t inform_parameters_nbre = sizeof(forced_inform_parameters) / sizeof(forced_inform_parameters[0]); + size_t i; + int j; + struct cwmp_dm_parameter cwmp_dm_param = { 0 }; + LIST_HEAD(list_inform); + for (i = 0; i < inform_parameters_nbre; i++) { + char *fault = cwmp_get_single_parameter_value(forced_inform_parameters[i], &cwmp_dm_param); + if (fault != NULL) + continue; + + // An empty connection url cause CDR test to break + if (strcmp(forced_inform_parameters[i], DM_CONN_REQ_URL) == 0 && cwmp_dm_param.value != NULL && strlen(cwmp_dm_param.value) == 0) { + CWMP_LOG(ERROR, "# Empty CR URL[%s] value", forced_inform_parameters[i]); + MXML_DELETE(xml); + return; + } + + if (xml_prepare_parameters_inform(&cwmp_dm_param, param_list, &size)) { + MXML_DELETE(xml); + return; + } + } + + for (j = 0; j < nbre_custom_inform; j++) { + char *fault = cwmp_get_single_parameter_value(custom_forced_inform_parameters[j], &cwmp_dm_param); + if (fault != NULL) + continue; + if (xml_prepare_parameters_inform(&cwmp_dm_param, param_list, &size)) { + MXML_DELETE(xml); + return; + } + } + + if (cwmp->is_boot == true) { + for (j = 0; j < nbre_boot_inform; j++) { + char *fault = cwmp_get_single_parameter_value(boot_inform_parameters[j], &cwmp_dm_param); + if (fault != NULL) + continue; + if (xml_prepare_parameters_inform(&cwmp_dm_param, param_list, &size)) { + MXML_DELETE(xml); + return; + } + } + } + + char c[256] = {0}; + if (snprintf(c, sizeof(c), "cwmp:ParameterValueStruct[%d]", size) == -1) { + MXML_DELETE(xml); + return; + } + + mxmlElementSetAttr(param_list, "xsi:type", "soap_enc:Array"); + mxmlElementSetAttr(param_list, "soap_enc:arrayType", c); + + *tree = xml; +} + +int cwmp_rpc_acs_prepare_message_inform(struct cwmp *cwmp, struct session *session, struct rpc *this) +{ + mxml_node_t *tree; + + if (session == NULL || this == NULL) + return -1; + + load_inform_xml_schema(&tree, cwmp, session); + + if (!tree) + goto error; + + session->tree_out = tree; + + return 0; + +error: + CWMP_LOG(ERROR, "Unable Prepare Message Inform", CWMP_BKP_FILE); + return -1; +} + +int cwmp_rpc_acs_parse_response_inform(struct cwmp *cwmp, struct session *session, struct rpc *this __attribute__((unused))) +{ + mxml_node_t *tree, *b; + int i = -1; + char *c; + const char *cwmp_urn; + + tree = session->tree_in; + if (!tree) + goto error; + b = mxmlFindElement(tree, tree, "MaxEnvelopes", NULL, NULL, MXML_DESCEND); + if (!b) + goto error; + b = mxmlWalkNext(b, tree, MXML_DESCEND_FIRST); + if (!b || mxmlGetType(b) != MXML_OPAQUE || !mxmlGetOpaque(b)) + goto error; + if (cwmp->conf.supported_amd_version == 1) { + cwmp->conf.amd_version = 1; + return 0; + } + b = mxmlFindElement(tree, tree, "UseCWMPVersion", NULL, NULL, MXML_DESCEND); + if (b && cwmp->conf.supported_amd_version >= 5) { //IF supported version !=5 acs response dosen't contain UseCWMPVersion + b = mxmlWalkNext(b, tree, MXML_DESCEND_FIRST); + if (!b || mxmlGetType(b) != MXML_OPAQUE || !mxmlGetOpaque(b)) + goto error; + c = (char *) mxmlGetOpaque(b); + if (c && *(c + 1) == '.') { + c += 2; + cwmp->conf.amd_version = atoi(c) + 1; + return 0; + } + goto error; + } + for (i = 0; cwmp_urls[i] != NULL; i++) { + cwmp_urn = cwmp_urls[i]; + c = (char *)xml__get_attribute_name_by_value(tree, cwmp_urn); + if (c && *(c + 5) == ':') { + break; + } + } + if (i == 0) { + cwmp->conf.amd_version = i + 1; + } else if (i >= 1 && i <= 3) { + switch (cwmp->conf.supported_amd_version) { + case 1: + cwmp->conf.amd_version = 1; //Already done + break; + case 2: + case 3: + case 4: + //MIN ACS CPE + if (cwmp->conf.supported_amd_version <= i + 1) + cwmp->conf.amd_version = cwmp->conf.supported_amd_version; + else + cwmp->conf.amd_version = i + 1; + break; + //(cwmp->supported_conf.amd_version < i+1) ?"cwmp->conf.amd_version":"i+1"; + case 5: + cwmp->conf.amd_version = i + 1; + break; + } + } else if (i >= 4) { + cwmp->conf.amd_version = cwmp->conf.supported_amd_version; + } + return 0; + +error: + return -1; +} + +int set_rpc_acs_to_supported(char *rpc_name) +{ + int i; + + for (i=1; i < __RPC_ACS_MAX; i++) { + if (strcmp(rpc_acs_methods[i].name, rpc_name) == 0) { + rpc_acs_methods[i].acs_support = RPC_ACS_SUPPORT; + return i; + } + } + return -1; +} + +void set_not_known_acs_support() +{ + int i; + for (i=1; i < __RPC_ACS_MAX; i++) { + if ((i != RPC_ACS_INFORM) && (rpc_acs_methods[i].acs_support == NOT_KNOWN)) + rpc_acs_methods[i].acs_support = RPC_ACS_NOT_SUPPORT; + } +} + +int cwmp_rpc_acs_parse_response_get_rpc_methods(struct cwmp *cwmp __attribute__((unused)), struct session *session, struct rpc *this __attribute__((unused))) +{ + mxml_node_t *tree, *b; + tree = session->tree_in; + b = mxmlFindElement(tree, tree, "cwmp:GetRPCMethodsResponse", NULL, NULL, MXML_DESCEND); + if (!b) + goto error; + + while (b) { + const char *node_opaque = mxmlGetOpaque(b); + mxml_node_t *parent_node = mxmlGetParent(b); + mxml_type_t node_type = mxmlGetType(b); + + if (node_type == MXML_OPAQUE && mxmlGetType(parent_node) == MXML_ELEMENT && node_opaque && strcmp((char *) mxmlGetElement(parent_node), "string") == 0) + set_rpc_acs_to_supported((char*)node_opaque); + + b = mxmlWalkNext(b, session->body_in, MXML_DESCEND); + } + set_not_known_acs_support(); + return 0; +error: + return -1; +} + +/* + * [RPC ACS]: GetRPCMethods + */ +int cwmp_rpc_acs_prepare_get_rpc_methods(struct cwmp *cwmp, struct session *session, struct rpc *rpc __attribute__((unused))) +{ + mxml_node_t *tree, *n; + + load_response_xml_schema(&tree); + if (!tree) + return -1; + + n = mxmlFindElement(tree, tree, "soap_env:Envelope", NULL, NULL, MXML_DESCEND); + if (!n) + return -1; + mxmlElementSetAttr(n, "xmlns:cwmp", cwmp_urls[(cwmp->conf.amd_version) - 1]); + + n = build_top_body_soap_request(tree, "GetRPCMethods"); + if (!n) + return -1; + + session->tree_out = tree; + + return 0; +} + +/* + * [RPC ACS]: TransferComplete + */ +int cwmp_rpc_acs_prepare_transfer_complete(struct cwmp *cwmp, struct session *session, struct rpc *rpc) +{ + mxml_node_t *tree, *n; + struct transfer_complete *p; + + p = (struct transfer_complete *)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->conf.amd_version) - 1]); + + n = build_top_body_soap_request(tree, "TransferComplete"); + if (!n) + goto error; + + struct xml_data_struct transfer_complete_xml_attrs = {0}; + + transfer_complete_xml_attrs.command_key = &p->command_key; + transfer_complete_xml_attrs.start_time = &p->start_time; + transfer_complete_xml_attrs.complete_time = &p->complete_time; + int faultcode = p->fault_code ? atoi(FAULT_CPE_ARRAY[p->fault_code].CODE) : 0; + transfer_complete_xml_attrs.fault_code = &faultcode; + char *faultstring = strdup(p->fault_code ? FAULT_CPE_ARRAY[p->fault_code].DESCRIPTION : ""); + transfer_complete_xml_attrs.fault_string = &faultstring; + + int fault = build_xml_node_data(SOAP_ACS_TRANSCOMPLETE, n, &transfer_complete_xml_attrs); + if (fault != CWMP_OK) + goto error; + + FREE(faultstring); + session->tree_out = tree; + + return 0; + +error: + return -1; +} + +/* + * [RPC ACS]: DUStateChangeComplete + */ +int cwmp_rpc_acs_prepare_du_state_change_complete(struct cwmp *cwmp, struct session *session, struct rpc *rpc) +{ + mxml_node_t *tree, *n; + struct du_state_change_complete *p; + + p = (struct du_state_change_complete *)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->conf.amd_version) - 1]); + + n = build_top_body_soap_request(tree, "DUStateChangeComplete"); + if (!n) + goto error; + + LIST_HEAD(opt_result_list); + cdu_operations_list_to_xml_data_list(&p->list_opresult, &opt_result_list); + + struct xml_data_struct cdu_complete_xml_attrs = {0}; + + cdu_complete_xml_attrs.command_key = &p->command_key; + cdu_complete_xml_attrs.data_list = &opt_result_list; + + int fault = build_xml_node_data(SOAP_DU_CHANGE_COMPLETE, n, &cdu_complete_xml_attrs); + if (fault != CWMP_OK) { + cwmp_free_all_xml_data_list(&opt_result_list); + goto error; + } + + cwmp_free_all_xml_data_list(&opt_result_list); + session->tree_out = tree; + return 0; + +error: + return -1; +} + +/* + * [RPC CPE]: GetParameterValues + */ +int cwmp_handle_rpc_cpe_get_parameter_values(struct session *session, struct rpc *rpc) +{ + mxml_node_t *b, *parameter_list = NULL; + int fault_code = FAULT_CPE_INTERNAL_ERROR; + int counter = 0; + char c[256]; + + if (session->tree_out == NULL) + goto fault; + + b = build_top_body_soap_response(session->tree_out, "GetParameterValues"); + + struct xml_data_struct gpv_resp_xml_attrs = {0}; + + char *xsi_type = "soap_enc:Array"; + gpv_resp_xml_attrs.xsi_type = &xsi_type; + gpv_resp_xml_attrs.parameter_list = ¶meter_list; + + int fault = build_xml_node_data(SOAP_RESP_GPV, b, &gpv_resp_xml_attrs); + if (fault != CWMP_OK) + goto fault; + + LIST_HEAD(gpv_xml_data_list); + + struct xml_data_struct gpv_xml_attrs = {0}; + gpv_xml_attrs.data_list = &gpv_xml_data_list; + struct xml_tag_validation gpv_validation[] = {{"string", VALIDATE_STR_SIZE, 0, 256}}; + gpv_xml_attrs.validations = gpv_validation; + gpv_xml_attrs.nbre_validations = 1; + + fault = load_xml_node_data(SOAP_REQ_GPV, session->body_in, &gpv_xml_attrs); + if (fault) { + fault_code = fault; + goto fault; + } + + struct xml_list_data *p = NULL; + struct list_head *l = gpv_xml_data_list.next; + while (l != &gpv_xml_data_list) { + p = list_entry(l, struct xml_list_data, list); + LIST_HEAD(parameters_list); + char *err = cwmp_get_parameter_values(p->param_name, ¶meters_list); + if (err && !is_obj_excluded(p->param_name)) { + fault_code = cwmp_get_fault_code_by_string(err); + goto fault; + } + LIST_HEAD(prameters_xml_list); + dm_parameter_list_to_xml_data_list(¶meters_list, &prameters_xml_list); + + struct xml_data_struct prmvalstrct_resp_xml_attrs = {0}; + prmvalstrct_resp_xml_attrs.counter = &counter; + prmvalstrct_resp_xml_attrs.data_list = &prameters_xml_list; + + fault = build_xml_node_data(SOAP_PARAM_STRUCT, parameter_list, &prmvalstrct_resp_xml_attrs); + if (fault != CWMP_OK) + goto fault; + + cwmp_free_all_dm_parameter_list(¶meters_list); + cwmp_free_all_xml_data_list(&prameters_xml_list); + l = l->next; + } + cwmp_free_all_xml_data_list(&gpv_xml_data_list); + b = mxmlFindElement(session->tree_out, session->tree_out, "ParameterList", NULL, NULL, MXML_DESCEND); + if (!b) + goto fault; + + if (snprintf(c, sizeof(c), "cwmp:ParameterValueStruct[%d]", counter) == -1) + goto fault; + + mxmlElementSetAttr(b, "soap_enc:arrayType", c); + + return 0; + +fault: + if (cwmp_create_fault_message(session, rpc, fault_code)) + return -1; + return 0; +} + +/* + * [RPC CPE]: GetParameterNames + */ +int cwmp_handle_rpc_cpe_get_parameter_names(struct session *session, struct rpc *rpc) +{ + mxml_node_t *n, *b, *parameter_list; + char *parameter_name = NULL; + bool next_level = true; + int counter = 0, fault_code = FAULT_CPE_INTERNAL_ERROR; + LIST_HEAD(parameters_list); + char c[256]; + + struct xml_data_struct gpn_xml_attrs = {0}; + + gpn_xml_attrs.next_level = &next_level; + gpn_xml_attrs.parameter_path = ¶meter_name; + struct xml_tag_validation gpn_validation[] = {{"ParameterPath", VALIDATE_STR_SIZE, 0, 256}, {"NextLevel", VALIDATE_BOOLEAN, 0, 0}}; + gpn_xml_attrs.validations = gpn_validation; + gpn_xml_attrs.nbre_validations = 2; + + int fault = load_xml_node_data(SOAP_REQ_GPN, session->body_in, &gpn_xml_attrs); + if (fault != CWMP_OK) { + fault_code = fault; + goto fault; + } + char *err = cwmp_get_parameter_names(parameter_name ? parameter_name : "", next_level, ¶meters_list); + if (err && !is_obj_excluded(parameter_name)) { + fault_code = cwmp_get_fault_code_by_string(err); + goto fault; + } + FREE(parameter_name); + + if (session->tree_out == NULL) + goto fault; + + n = build_top_body_soap_response(session->tree_out, "GetParameterNames"); + + if (!n){ + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + parameter_list = mxmlNewElement(n, "ParameterList"); + if (!parameter_list){ + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + mxmlElementSetAttr(parameter_list, "xsi:type", "soap_enc:Array"); + + LIST_HEAD(prameters_xml_list); + dm_parameter_list_to_xml_data_list(¶meters_list, &prameters_xml_list); + + struct xml_data_struct gpv_resp_xml_attrs = {0}; + gpv_resp_xml_attrs.data_list = &prameters_xml_list; + gpv_resp_xml_attrs.counter = &counter; + + fault = build_xml_node_data(SOAP_RESP_GPN, parameter_list, &gpv_resp_xml_attrs); + if (fault != CWMP_OK) + goto fault; + + cwmp_free_all_dm_parameter_list(¶meters_list); + cwmp_free_all_xml_data_list(&prameters_xml_list); + + b = mxmlFindElement(session->tree_out, session->tree_out, "ParameterList", NULL, NULL, MXML_DESCEND); + if (!b) + goto fault; + + if (snprintf(c, sizeof(c), "cwmp:ParameterInfoStruct[%d]", counter) == -1) + goto fault; + + mxmlElementSetAttr(b, "soap_enc:arrayType", c); + return 0; + +fault: + cwmp_free_all_dm_parameter_list(¶meters_list); + if (cwmp_create_fault_message(session, rpc, fault_code)) + return -1; + return 0; +} + +/* + * [RPC CPE]: GetParameterAttributes + */ +int cwmp_handle_rpc_cpe_get_parameter_attributes(struct session *session, struct rpc *rpc) +{ + mxml_node_t *n, *parameter_list, *b; + int counter = 0, fault_code = FAULT_CPE_INTERNAL_ERROR; + char c[256]; + b = session->body_in; + + n = build_top_body_soap_response(session->tree_out, "GetParameterAttributes"); + if (!n) + goto fault; + + parameter_list = mxmlNewElement(n, "ParameterList"); + if (!parameter_list) + goto fault; + + mxmlElementSetAttr(parameter_list, "xsi:type", "soap_enc:Array"); + + LIST_HEAD(gpa_xml_data_list); + + + struct xml_data_struct gpa_xml_attrs = {0}; + gpa_xml_attrs.data_list = &gpa_xml_data_list; + struct xml_tag_validation gpa_validation[] = {{"string", VALIDATE_STR_SIZE, 0, 256}}; + gpa_xml_attrs.validations = gpa_validation; + gpa_xml_attrs.nbre_validations = 1; + + int fault = load_xml_node_data(SOAP_REQ_GPA, b, &gpa_xml_attrs); + if (fault) { + fault_code = fault; + goto fault; + } + + struct xml_list_data *p = NULL; + struct list_head*l= gpa_xml_data_list.next; + while (l != &gpa_xml_data_list) { + p = list_entry(l, struct xml_list_data, list); + LIST_HEAD(parameters_list); + char *err = cwmp_get_parameter_attributes(p->param_name, ¶meters_list); + if (err && !is_obj_excluded(p->param_name)) { + fault_code = cwmp_get_fault_code_by_string(err); + cwmp_free_all_dm_parameter_list(¶meters_list); + cwmp_free_all_xml_data_list(&gpa_xml_data_list); + goto fault; + } + LIST_HEAD(parameters_xml_list); + dm_parameter_list_to_xml_data_list(¶meters_list, ¶meters_xml_list); + + struct xml_data_struct gpv_resp_xml_attrs = {0}; + gpv_resp_xml_attrs.counter = &counter; + gpv_resp_xml_attrs.data_list = ¶meters_xml_list; + fault = build_xml_node_data(SOAP_RESP_GPA, parameter_list, &gpv_resp_xml_attrs); + if (fault != CWMP_OK) + goto fault; + + cwmp_free_all_xml_data_list(¶meters_xml_list); + l = l->next; + } + cwmp_free_all_xml_data_list(&gpa_xml_data_list); + + b = mxmlFindElement(session->tree_out, session->tree_out, "ParameterList", NULL, NULL, MXML_DESCEND); + if (!b) + goto fault; + + if (snprintf(c, sizeof(c), "cwmp:ParameterAttributeStruct[%d]", counter) == -1) + goto fault; + + mxmlElementSetAttr(b, "soap_enc:arrayType", c); + return 0; + +fault: + if (cwmp_create_fault_message(session, rpc, fault_code)) + return -1; + return 0; +} + +/* + * [RPC CPE]: SetParameterValues + */ +int is_duplicated_parameter(mxml_node_t *param_node, struct session *session) +{ + mxml_node_t *b = param_node; + while ((b = mxmlWalkNext(b, session->body_in, MXML_DESCEND))) { + const char *node_opaque = mxmlGetOpaque(b); + mxml_node_t *parent = mxmlGetParent(b); + mxml_type_t node_type = mxmlGetType(b); + + if (node_type == MXML_OPAQUE && node_opaque && mxmlGetType(parent) == MXML_ELEMENT && !strcmp(mxmlGetElement(parent), "Name")) { + if (strcmp(node_opaque, mxmlGetOpaque(param_node)) == 0) + return -1; + } + } + return 0; +} + +int cwmp_handle_rpc_cpe_set_parameter_values(struct session *session, struct rpc *rpc) +{ + mxml_node_t *b = NULL; + char *parameter_key = NULL; + int fault_code = FAULT_CPE_INTERNAL_ERROR, ret = 0; + + LIST_HEAD(xml_list_set_param_value); + LIST_HEAD(list_set_param_value); + LIST_HEAD(list_fault_param); + + rpc->list_set_value_fault = &list_fault_param; + struct xml_tag_validation spv_validation[] = {{"ParameterKey", VALIDATE_STR_SIZE, 0, 32}, {"Name", VALIDATE_STR_SIZE, 0, 256}}; + struct xml_data_struct spv_xml_attrs = {0}; + spv_xml_attrs.parameter_key = ¶meter_key; + spv_xml_attrs.data_list = &xml_list_set_param_value; + spv_xml_attrs.validations = spv_validation; + spv_xml_attrs.nbre_validations = 2; + + int fault = load_xml_node_data(SOAP_REQ_SPV, session->body_in, &spv_xml_attrs); + if (fault) { + fault_code = fault; + goto fault; + } + + xml_data_list_to_dm_parameter_list(&xml_list_set_param_value, &list_set_param_value); + + int flag = 0; + if (transaction_id == 0) { + if (!cwmp_transaction_start("cwmp")) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + } + + fault_code = cwmp_set_multiple_parameters_values(&list_set_param_value, parameter_key ? parameter_key : "", &flag, rpc->list_set_value_fault); + if (fault_code != FAULT_CPE_NO_FAULT) + goto fault; + + FREE(parameter_key); + struct cwmp_dm_parameter *param_value; + // cppcheck-suppress unknownMacro + list_for_each_entry (param_value, &list_set_param_value, list) + set_diagnostic_parameter_structure_value(param_value->name, param_value->value); + + cwmp_free_all_xml_data_list(&xml_list_set_param_value); + cwmp_free_all_dm_parameter_list(&list_set_param_value); + + b = build_top_body_soap_response(session->tree_out, "SetParameterValues"); + + if (!b) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + int status = 1; + + struct xml_data_struct spv_resp_xml_attrs = {.status = &status}; + fault = build_xml_node_data(SOAP_RESP_SPV, b, &spv_resp_xml_attrs); + if (fault) + goto fault; + + if (!cwmp_transaction_commit()) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + cwmp_set_end_session(flag | END_SESSION_RESTART_SERVICES | END_SESSION_SET_NOTIFICATION_UPDATE | END_SESSION_RELOAD); + return 0; + +fault: + cwmp_free_all_dm_parameter_list(&list_set_param_value); + if (cwmp_create_fault_message(session, rpc, fault_code)) + ret = CWMP_XML_ERR; + + cwmp_free_all_list_param_fault(rpc->list_set_value_fault); + if (transaction_id) { + cwmp_transaction_abort(); + transaction_id = 0; + } + return ret; +} + +/* + * [RPC CPE]: SetParameterAttributes + */ +int cwmp_handle_rpc_cpe_set_parameter_attributes(struct session *session, struct rpc *rpc) +{ + mxml_node_t *n; + int fault_code = FAULT_CPE_INTERNAL_ERROR, ret = 0; + char c[256]; + + if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "SetParameterAttributes") == -1) + goto fault; + + n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); + + if (!n) + goto fault; + + LIST_HEAD(prameters_xml_list); + struct xml_data_struct spa_xml_attrs = {0}; + spa_xml_attrs.data_list = &prameters_xml_list; + struct xml_tag_validation spa_validation[] = {{"Name", VALIDATE_STR_SIZE, 0, 256}, {"NotificationChange", VALIDATE_BOOLEAN, 0, 0}, {"Notification", VALIDATE_INT_RANGE, 0, 6}}; + spa_xml_attrs.validations = spa_validation; + spa_xml_attrs.nbre_validations = 3; + + fault_code = load_xml_node_data(SOAP_REQ_SPA, n, &spa_xml_attrs); + if (fault_code) + goto fault; + struct list_head *l = prameters_xml_list.next; + struct xml_list_data *p = NULL; + while (l != &prameters_xml_list) { + p = list_entry(l, struct xml_list_data, list); + if (p->param_name && p->notification_change) { + char *err = cwmp_set_parameter_attributes(p->param_name, p->notification); + if (err) { + fault_code = cwmp_get_fault_code_by_string(err); + goto fault; + } + } + l = l->next; + } + cwmp_free_all_xml_data_list(&prameters_xml_list); + + mxml_node_t *resp = build_top_body_soap_response(session->tree_out, "SetParameterAttributes"); + if (!resp) + goto fault; + + cwmp_set_end_session(END_SESSION_SET_NOTIFICATION_UPDATE | END_SESSION_RESTART_SERVICES | END_SESSION_INIT_NOTIFY); + return 0; + +fault: + if (cwmp_create_fault_message(session, rpc, fault_code)) + ret = CWMP_XML_ERR; + + return ret; +} + +/* + * [RPC CPE]: AddObject + */ +int cwmp_handle_rpc_cpe_add_object(struct session *session, struct rpc *rpc) +{ + mxml_node_t *b; + char *object_name = NULL; + char *parameter_key = NULL; + int fault_code = FAULT_CPE_INTERNAL_ERROR, ret = 0; + char *instance = NULL; + + struct xml_data_struct add_obj_xml_attrs = {0}; + add_obj_xml_attrs.object_name = &object_name; + add_obj_xml_attrs.parameter_key = ¶meter_key; + struct xml_tag_validation gpn_validation[] = {{"ParameterKey", VALIDATE_STR_SIZE, 0, 32}, {"ObjectName", VALIDATE_STR_SIZE, 0, 256}}; + add_obj_xml_attrs.validations = gpn_validation; + add_obj_xml_attrs.nbre_validations = 2; + + int fault = load_xml_node_data(SOAP_REQ_ADDOBJ, session->body_in, &add_obj_xml_attrs); + + if (fault) { + fault_code = fault; + goto fault; + } + + if (transaction_id == 0) { + if (!cwmp_transaction_start("cwmp")) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + } + + if (object_name) { + char *err = cwmp_add_object(object_name, parameter_key ? parameter_key : "", &instance); + if (err) { + fault_code = cwmp_get_fault_code_by_string(err); + goto fault; + } + } else { + fault_code = FAULT_CPE_INVALID_PARAMETER_NAME; + goto fault; + } + if (instance == NULL) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + b = build_top_body_soap_response(session->tree_out, "AddObject"); + + if (!b) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + int instance_int = atoi(instance); + int status = 1; + struct xml_data_struct add_resp_xml_attrs = {0}; + add_resp_xml_attrs.instance = &instance_int; + add_resp_xml_attrs.status = &status; + + fault = build_xml_node_data(SOAP_RESP_ADDOBJ, b, &add_resp_xml_attrs); + if (fault != CWMP_OK) + goto fault; + + if (!cwmp_transaction_commit()) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + char *object_path = NULL; + icwmp_asprintf(&object_path, "%s%s.", object_name, instance); + cwmp_set_parameter_attributes(object_path, 0); + FREE(object_name); + FREE(parameter_key); + FREE(instance); + cwmp_set_end_session(END_SESSION_RESTART_SERVICES); + return 0; + +fault: + FREE(object_name); + FREE(parameter_key); + FREE(instance); + if (cwmp_create_fault_message(session, rpc, fault_code)) + ret = CWMP_XML_ERR; + if (transaction_id) { + cwmp_transaction_abort(); + transaction_id = 0; + } + return ret; +} + +/* + * [RPC CPE]: DeleteObject + */ +int cwmp_handle_rpc_cpe_delete_object(struct session *session, struct rpc *rpc) +{ + mxml_node_t *b; + char *object_name = NULL; + char *parameter_key = NULL; + int fault_code = FAULT_CPE_INTERNAL_ERROR, ret = 0; + + struct xml_data_struct del_obj_xml_attrs = {0}; + del_obj_xml_attrs.object_name = &object_name; + del_obj_xml_attrs.parameter_key = ¶meter_key; + struct xml_tag_validation gpn_validation[] = {{"ParameterKey", VALIDATE_STR_SIZE, 0, 32}, {"ObjectName", VALIDATE_STR_SIZE, 0, 256}}; + del_obj_xml_attrs.validations = gpn_validation; + del_obj_xml_attrs.nbre_validations = 2; + + int fault = load_xml_node_data(SOAP_REQ_DELOBJ, session->body_in, &del_obj_xml_attrs); + + if (fault) { + fault_code = fault; + goto fault; + } + + if (transaction_id == 0) { + if (!cwmp_transaction_start("cwmp")) + goto fault; + } + if (object_name) { + char *err = cwmp_delete_object(object_name, parameter_key ? parameter_key : ""); + if (err) { + fault_code = cwmp_get_fault_code_by_string(err); + goto fault; + } + } else { + fault_code = FAULT_CPE_INVALID_PARAMETER_NAME; + goto fault; + } + + b = build_top_body_soap_response(session->tree_out, "DeleteObject"); + + if (!b) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + int status = 1; + struct xml_data_struct add_resp_xml_attrs = {0}; + add_resp_xml_attrs.status = &status; + + fault = build_xml_node_data(SOAP_RESP_DELOBJ, b, &add_resp_xml_attrs); + if (fault != CWMP_OK) + goto fault; + + if (!cwmp_transaction_commit()) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + FREE(object_name); + FREE(parameter_key); + cwmp_set_end_session(END_SESSION_RESTART_SERVICES); + return 0; + +fault: + FREE(object_name); + FREE(parameter_key); + if (cwmp_create_fault_message(session, rpc, fault_code)) + ret = CWMP_XML_ERR; + if (transaction_id) { + cwmp_transaction_abort(); + transaction_id = 0; + } + return ret; +} + +/* + * [RPC CPE]: GetRPCMethods + */ +int cwmp_handle_rpc_cpe_get_rpc_methods(struct session *session, struct rpc *rpc) +{ + mxml_node_t *n, *method_list; + int i, counter = 0; + mxml_node_t *b = session->body_in; + char c[128]; + + n = build_top_body_soap_response(session->tree_out, "GetRPCMethods"); + + if (!n) + goto fault; + + + LIST_HEAD(rpcs_list); + + for (i = 1; i < __RPC_CPE_MAX; i++) { + if (i != RPC_CPE_FAULT) { + struct xml_list_data *xml_data = calloc(1, sizeof(struct xml_list_data)); + xml_data->rpc_name = strdup(rpc_cpe_methods[i].name); + list_add(&(xml_data->list), &rpcs_list); + counter++; + } + } + + method_list = mxmlNewElement(n, "MethodList"); + if (!method_list) + goto fault; + + struct xml_data_struct getrpc_resp_xml_attrs = {0}; + getrpc_resp_xml_attrs.data_list = &rpcs_list; + + int fault = build_xml_node_data(SOAP_RESP_GETRPC, method_list, &getrpc_resp_xml_attrs); + if (fault != CWMP_OK) + goto fault; + + cwmp_free_all_xml_data_list(&rpcs_list); + b = mxmlFindElement(session->tree_out, session->tree_out, "MethodList", NULL, NULL, MXML_DESCEND); + if (!b) + goto fault; + + mxmlElementSetAttr(b, "xsi:type", "soap_enc:Array"); + if (snprintf(c, sizeof(c), "xsd:string[%d]", counter) == -1) + goto fault; + + mxmlElementSetAttr(b, "soap_enc:arrayType", c); + + return 0; + +fault: + if (cwmp_create_fault_message(session, rpc, FAULT_CPE_INTERNAL_ERROR)) + goto error; + return 0; + +error: + return -1; +} + +/* + * [RPC CPE]: FactoryReset + */ +int cwmp_handle_rpc_cpe_factory_reset(struct session *session, struct rpc *rpc) +{ + mxml_node_t *b; + + b = build_top_body_soap_response(session->tree_out, "FactoryReset"); + + if (!b) + goto fault; + + cwmp_set_end_session(END_SESSION_FACTORY_RESET); + + return 0; + +fault: + if (cwmp_create_fault_message(session, rpc, FAULT_CPE_INTERNAL_ERROR)) + goto error; + return 0; + +error: + return -1; +} + +/* + * [RPC CPE]: X_FactoryResetSoft + */ +int cwmp_handle_rpc_cpe_x_factory_reset_soft(struct session *session, struct rpc *rpc) +{ + mxml_node_t *b; + + b = build_top_body_soap_response(session->tree_out, "X_FactoryResetSoft"); + + if (!b) + goto fault; + + cwmp_set_end_session(END_SESSION_X_FACTORY_RESET_SOFT); + + return 0; + +fault: + if (cwmp_create_fault_message(session, rpc, FAULT_CPE_INTERNAL_ERROR)) + goto error; + return 0; + +error: + return -1; +} + +/* + * [RPC CPE]: CancelTransfer + */ +int cwmp_handle_rpc_cpe_cancel_transfer(struct session *session, struct rpc *rpc) +{ + mxml_node_t *b; + char *command_key = NULL; + int fault_code = FAULT_CPE_INTERNAL_ERROR; + b = session->body_in; + + struct xml_data_struct canceltrancer_obj_xml_attrs = {0}; + canceltrancer_obj_xml_attrs.command_key = &command_key; + struct xml_tag_validation canceltransfer_validation[] = {{"CommandKey", VALIDATE_STR_SIZE, 0, 32}}; + canceltrancer_obj_xml_attrs.validations = canceltransfer_validation; + canceltrancer_obj_xml_attrs.nbre_validations = 1; + + fault_code = load_xml_node_data(SOAP_REQ_CANCELTRANSFER, session->body_in, &canceltrancer_obj_xml_attrs); + + if (command_key) + cancel_transfer(command_key); + + if (fault_code) + goto fault; + + b = build_top_body_soap_response(session->tree_out, "CancelTransfer"); + + if (!b) { + fault_code = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + FREE(command_key); + return 0; + +fault: + FREE(command_key); + if (cwmp_create_fault_message(session, rpc, fault_code)) + goto error; + return 0; + +error: + return -1; +} + +int cancel_transfer(char *key) +{ + struct list_head *ilist, *q; + + if (list_download.next != &(list_download)) { + list_for_each_safe (ilist, q, &(list_download)) { + struct download *pdownload = list_entry(ilist, struct download, list); + if (strcmp(pdownload->command_key, key) == 0) { + pthread_mutex_lock(&mutex_download); + bkp_session_delete_download(pdownload); + bkp_session_save(); + list_del(&(pdownload->list)); + if (pdownload->scheduled_time != 0) + count_download_queue--; + cwmp_free_download_request(pdownload); + pthread_mutex_unlock(&mutex_download); + } + } + } + if (list_upload.next != &(list_upload)) { + list_for_each_safe (ilist, q, &(list_upload)) { + struct upload *pupload = list_entry(ilist, struct upload, list); + if (strcmp(pupload->command_key, key) == 0) { + pthread_mutex_lock(&mutex_upload); + bkp_session_delete_upload(pupload); + bkp_session_save(); + list_del(&(pupload->list)); + if (pupload->scheduled_time != 0) + count_download_queue--; + cwmp_free_upload_request(pupload); + pthread_mutex_unlock(&mutex_upload); + } + } + } + // Cancel schedule download + return CWMP_OK; +} + +/* + * [RPC CPE]: Reboot + */ +int cwmp_handle_rpc_cpe_reboot(struct session *session, struct rpc *rpc) +{ + mxml_node_t *b; + struct event_container *event_container; + char *command_key = NULL; + int fault_code = FAULT_CPE_INTERNAL_ERROR; + b = session->body_in; + + struct xml_data_struct reboot_obj_xml_attrs = {0}; + reboot_obj_xml_attrs.command_key = &command_key; + struct xml_tag_validation reboot_validation[] = {{"CommandKey", VALIDATE_STR_SIZE, 0, 32}}; + reboot_obj_xml_attrs.validations = reboot_validation; + reboot_obj_xml_attrs.nbre_validations = 1; + + fault_code = load_xml_node_data(SOAP_REQ_REBOOT, session->body_in, &reboot_obj_xml_attrs); + + if (fault_code) + goto fault; + + commandKey = icwmp_strdup(command_key); + + pthread_mutex_lock(&(cwmp_main.mutex_session_queue)); + event_container = cwmp_add_event_container(&cwmp_main, EVENT_IDX_M_Reboot, command_key); + if (event_container == NULL) { + pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); + goto fault; + } + cwmp_save_event_container(event_container); + pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); + + b = build_top_body_soap_response(session->tree_out, "Reboot"); + + if (!b) + goto fault; + + cwmp_set_end_session(END_SESSION_REBOOT); + + FREE(command_key); + return 0; + +fault: +FREE(command_key); + if (cwmp_create_fault_message(session, rpc, fault_code)) + goto error; + return 0; + +error: + return -1; +} + +/* + * [RPC CPE]: ScheduleInform + */ +int cwmp_handle_rpc_cpe_schedule_inform(struct session *session, struct rpc *rpc) +{ + mxml_node_t *n; + char *command_key = NULL; + struct schedule_inform *schedule_inform; + time_t scheduled_time; + struct list_head *ilist; + int fault = FAULT_CPE_NO_FAULT; + int delay_seconds = 0; + + + pthread_mutex_lock(&mutex_schedule_inform); + + struct xml_data_struct schedinform_obj_xml_attrs = {0}; + schedinform_obj_xml_attrs.command_key = &command_key; + schedinform_obj_xml_attrs.delay_seconds = (long int*)&delay_seconds; + struct xml_tag_validation schedinform_validation[] = {{"CommandKey", VALIDATE_STR_SIZE, 0, 32}, {"DelaySeconds", VALIDATE_UNINT, 0, 0}}; + schedinform_obj_xml_attrs.validations = schedinform_validation; + schedinform_obj_xml_attrs.nbre_validations = 2; + + fault = load_xml_node_data(SOAP_REQ_SCHEDINF, session->body_in, &schedinform_obj_xml_attrs); + + FREE(command_key); + if (fault) + goto fault; + + if (count_schedule_inform_queue >= MAX_SCHEDULE_INFORM_QUEUE) { + fault = FAULT_CPE_RESOURCES_EXCEEDED; + pthread_mutex_unlock(&mutex_schedule_inform); + goto fault; + } + count_schedule_inform_queue++; + + scheduled_time = time(NULL) + delay_seconds; + list_for_each (ilist, &(list_schedule_inform)) { + schedule_inform = list_entry(ilist, struct schedule_inform, list); + if (schedule_inform->scheduled_time >= scheduled_time) { + break; + } + } + + n = build_top_body_soap_response(session->tree_out, "ScheduleInform"); + + if (!n) + goto fault; + + CWMP_LOG(INFO, "Schedule inform event will start in %us", delay_seconds); + schedule_inform = calloc(1, sizeof(struct schedule_inform)); + if (schedule_inform == NULL) { + pthread_mutex_unlock(&mutex_schedule_inform); + goto fault; + } + schedule_inform->commandKey = strdup(command_key); + schedule_inform->scheduled_time = scheduled_time; + list_add(&(schedule_inform->list), ilist->prev); + bkp_session_insert_schedule_inform(schedule_inform->scheduled_time, schedule_inform->commandKey); + bkp_session_save(); + pthread_mutex_unlock(&mutex_schedule_inform); + pthread_cond_signal(&threshold_schedule_inform); + +success: + return 0; + +fault: + if (cwmp_create_fault_message(session, rpc, fault ? fault : FAULT_CPE_INTERNAL_ERROR)) + goto error; + goto success; + +error: + return -1; +} + +/* + * [RPC CPE]: ChangeDuState + */ +int cwmp_handle_rpc_cpe_change_du_state(struct session *session, struct rpc *rpc) +{ + mxml_node_t *n, *t; + struct change_du_state *change_du_state = NULL; + int error = FAULT_CPE_NO_FAULT; + char c[256]; + + if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "ChangeDUState") == -1) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); + + if (!n) + return -1; + + change_du_state = calloc(1, sizeof(struct change_du_state)); + if (change_du_state == NULL) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + INIT_LIST_HEAD(&(change_du_state->list_operation)); + change_du_state->timeout = time(NULL); + + LIST_HEAD(xml_list_operations); + struct xml_data_struct cdu_xml_attrs = {0}; + cdu_xml_attrs.command_key = &change_du_state->command_key; + cdu_xml_attrs.data_list = &xml_list_operations; + struct xml_tag_validation cdu_validation[] = {{"CommandKey", VALIDATE_STR_SIZE, 0, 32}, {"URL", VALIDATE_STR_SIZE, 0, 1024}, {"UUID", VALIDATE_STR_SIZE, 0, 36}, {"Username", VALIDATE_STR_SIZE, 0, 256}, {"Password", VALIDATE_STR_SIZE, 0, 256}, {"ExecutionEnvRef", VALIDATE_STR_SIZE, 0, 256}, {"Version", VALIDATE_STR_SIZE, 0, 32}}; + cdu_xml_attrs.validations = cdu_validation; + cdu_xml_attrs.nbre_validations = 7; + + error = load_xml_node_data(SOAP_REQ_CDU, n, &cdu_xml_attrs); + + if (error) + goto fault; + + xml_data_list_to_cdu_operations_list(&xml_list_operations, &change_du_state->list_operation); + + t = build_top_body_soap_response(session->tree_out, "ChangeDUState"); + + if (!t) + goto fault; + + if (error == FAULT_CPE_NO_FAULT) { + pthread_mutex_lock(&mutex_change_du_state); + list_add_tail(&(change_du_state->list), &(list_change_du_state)); + bkp_session_insert_change_du_state(change_du_state); + bkp_session_save(); + pthread_mutex_unlock(&mutex_change_du_state); + pthread_cond_signal(&threshold_change_du_state); + } + return 0; + +fault: + cwmp_free_change_du_state_request(change_du_state); + if (cwmp_create_fault_message(session, rpc, error)) + goto error; + return 0; + +error: + return -1; +} + +/* + * [RPC CPE]: Download + */ +int cwmp_handle_rpc_cpe_download(struct session *session, struct rpc *rpc) +{ + mxml_node_t *n; + char c[256]; + int error = FAULT_CPE_NO_FAULT; + struct download *download = NULL, *idownload; + struct list_head *ilist; + time_t scheduled_time = 0; + time_t download_delay = 0; + + if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "Download") == -1) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); + + if (!n) + return -1; + + download = calloc(1, sizeof(struct download)); + if (download == NULL) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + struct xml_data_struct download_xml_attrs = {0}; + download_xml_attrs.command_key = &download->command_key; + download_xml_attrs.url = &download->url; + download_xml_attrs.username = &download->username; + download_xml_attrs.password = &download->password; + download_xml_attrs.delay_seconds = (long int*)&download_delay; + download_xml_attrs.file_type = &download->file_type; + download_xml_attrs.file_size = &download->file_size; + + struct xml_tag_validation download_validation[] = {{"CommandKey", VALIDATE_STR_SIZE, 0, 32}, {"FileType", VALIDATE_STR_SIZE, 0, 64}, {"URL", VALIDATE_STR_SIZE, 0, 256}, {"Username", VALIDATE_STR_SIZE, 0, 256}, {"Password", VALIDATE_STR_SIZE, 0, 256}, {"FileSize", VALIDATE_UNINT, 0, 0}, {"DelaySeconds", VALIDATE_UNINT, 0, 0}}; + download_xml_attrs.validations = download_validation; + download_xml_attrs.nbre_validations = 7; + + int fault = load_xml_node_data(SOAP_REQ_DOWNLOAD, n, &download_xml_attrs); + + if (fault) { + error = fault; + goto fault; + } + + if (strcmp(download->file_type, FIRMWARE_UPGRADE_IMAGE_FILE_TYPE) && strcmp(download->file_type, WEB_CONTENT_FILE_TYPE) && strcmp(download->file_type, VENDOR_CONFIG_FILE_TYPE) && strcmp(download->file_type, TONE_FILE_TYPE) && strcmp(download->file_type, RINGER_FILE_TYPE) && strcmp(download->file_type, STORED_FIRMWARE_IMAGE_FILE_TYPE)) { + error = FAULT_CPE_INVALID_ARGUMENTS; + } else if (count_download_queue >= MAX_DOWNLOAD_QUEUE) { + error = FAULT_CPE_RESOURCES_EXCEEDED; + } else if (download->url == NULL || (strcmp(download->url, "") == 0)) { + error = FAULT_CPE_REQUEST_DENIED; + } else if (strstr(download->url, "@") != NULL) { + error = FAULT_CPE_INVALID_ARGUMENTS; + } else if (strncmp(download->url, DOWNLOAD_PROTOCOL_HTTP, strlen(DOWNLOAD_PROTOCOL_HTTP)) != 0 && strncmp(download->url, DOWNLOAD_PROTOCOL_HTTPS, strlen(DOWNLOAD_PROTOCOL_HTTPS)) != 0 && strncmp(download->url, DOWNLOAD_PROTOCOL_FTP, strlen(DOWNLOAD_PROTOCOL_FTP)) != 0) { + error = FAULT_CPE_FILE_TRANSFER_UNSUPPORTED_PROTOCOL; + } + if (error != FAULT_CPE_NO_FAULT) + goto fault; + + mxml_node_t *t = build_top_body_soap_response(session->tree_out, "Download"); + char *start_time = "0001-01-01T00:00:00+00:00"; + char *complete_time = "0001-01-01T00:00:00+00:00"; + int status = 1; + + struct xml_data_struct download_resp_xml_attrs = {0}; + download_resp_xml_attrs.status = &status; + download_resp_xml_attrs.start_time = &start_time; + download_resp_xml_attrs.complete_time = &complete_time; + fault = build_xml_node_data(SOAP_RESP_DOWNLOAD, t, &download_resp_xml_attrs); + if (fault != CWMP_OK) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + if (error == FAULT_CPE_NO_FAULT) { + pthread_mutex_lock(&mutex_download); + if (download_delay != 0) + scheduled_time = time(NULL) + download_delay + PROCESSING_DELAY; + + list_for_each (ilist, &(list_download)) { + idownload = list_entry(ilist, struct download, list); + if (idownload->scheduled_time >= scheduled_time) { + break; + } + } + list_add(&(download->list), ilist->prev); + if (download_delay != 0) { + count_download_queue++; + download->scheduled_time = scheduled_time; + } + bkp_session_insert_download(download); + bkp_session_save(); + if (download_delay != 0) { + CWMP_LOG(INFO, "Download will start in %us", download_delay); + } else { + CWMP_LOG(INFO, "Download will start at the end of session"); + } + + pthread_mutex_unlock(&mutex_download); + pthread_cond_signal(&threshold_download); + } + + return 0; + +fault: + cwmp_free_download_request(download); + if (cwmp_create_fault_message(session, rpc, error)) + return -1; + return 0; +} + +/* + * [RPC CPE]: ScheduleDownload + */ +int cwmp_handle_rpc_cpe_schedule_download(struct session *session, struct rpc *rpc) +{ + mxml_node_t *n, *t; + char c[256]; + int i = 0, j = 0; + int error = FAULT_CPE_NO_FAULT; + struct download *schedule_download = NULL; + time_t schedule_download_delay[4] = { 0, 0, 0, 0 }; + + if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "ScheduleDownload") == -1) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); + + if (!n) + return -1; + + schedule_download = calloc(1, sizeof(struct download)); + if (schedule_download == NULL) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + struct xml_data_struct sched_download_xml_attrs = {0}; + sched_download_xml_attrs.command_key = &schedule_download->command_key; + sched_download_xml_attrs.url = &schedule_download->url; + sched_download_xml_attrs.username = &schedule_download->username; + sched_download_xml_attrs.password = &schedule_download->password; + sched_download_xml_attrs.file_type = &schedule_download->file_type; + sched_download_xml_attrs.file_size = &schedule_download->file_size; + + struct xml_tag_validation scheddownload_validation[] = {{"CommandKey", VALIDATE_STR_SIZE, 0, 32}, {"FileType", VALIDATE_STR_SIZE, 0, 64}, {"URL", VALIDATE_STR_SIZE, 0, 256}, {"Username", VALIDATE_STR_SIZE, 0, 256}, {"Password", VALIDATE_STR_SIZE, 0, 256}, {"FileSize", VALIDATE_UNINT, 0, 0}}; + sched_download_xml_attrs.validations = scheddownload_validation; + sched_download_xml_attrs.nbre_validations = 6; + + LIST_HEAD(time_window_intervals); + sched_download_xml_attrs.data_list = &time_window_intervals; + + error = load_xml_node_data(SOAP_REQ_SCHEDDOWN, n, &sched_download_xml_attrs); + + if (error) + goto fault; + + struct xml_list_data *list_data = NULL; + if (time_window_intervals.next) { + list_data = container_of(time_window_intervals.next, struct xml_list_data, list); + schedule_download->timewindowstruct[0].windowmode = list_data->windowmode; + schedule_download->timewindowstruct[0].usermessage = list_data->usermessage; + schedule_download->timewindowstruct[0].maxretries = list_data->max_retries; + schedule_download->timewindowstruct[0].windowstart = list_data->windowstart; + schedule_download->timewindowstruct[0].windowend = list_data->windowend; + if (time_window_intervals.next->next) { + list_data = container_of(time_window_intervals.next->next, struct xml_list_data, list); + schedule_download->timewindowstruct[1].windowmode = list_data->windowmode; + schedule_download->timewindowstruct[1].usermessage = list_data->usermessage; + schedule_download->timewindowstruct[1].maxretries = list_data->max_retries; + schedule_download->timewindowstruct[1].windowstart = list_data->windowstart; + schedule_download->timewindowstruct[1].windowend = list_data->windowend; + } + } + + if (strcmp(schedule_download->file_type, FIRMWARE_UPGRADE_IMAGE_FILE_TYPE) && strcmp(schedule_download->file_type, WEB_CONTENT_FILE_TYPE) && strcmp(schedule_download->file_type, VENDOR_CONFIG_FILE_TYPE) && strcmp(schedule_download->file_type, TONE_FILE_TYPE) && strcmp(schedule_download->file_type, RINGER_FILE_TYPE) && strcmp(schedule_download->file_type, STORED_FIRMWARE_IMAGE_FILE_TYPE)) { + error = FAULT_CPE_INVALID_ARGUMENTS; + } else if ((strcmp(schedule_download->timewindowstruct[0].windowmode, "1 At Any Time") && strcmp(schedule_download->timewindowstruct[0].windowmode, "2 Immediately") && strcmp(schedule_download->timewindowstruct[0].windowmode, "3 When Idle")) || (strcmp(schedule_download->timewindowstruct[1].windowmode, "1 At Any Time") && strcmp(schedule_download->timewindowstruct[1].windowmode, "2 Immediately") && strcmp(schedule_download->timewindowstruct[1].windowmode, "3 When Idle"))) { + error = FAULT_CPE_REQUEST_DENIED; + } else if (count_download_queue >= MAX_DOWNLOAD_QUEUE) { + error = FAULT_CPE_RESOURCES_EXCEEDED; + } else if (schedule_download->url == NULL || (strcmp(schedule_download->url, "") == 0)) { + error = FAULT_CPE_REQUEST_DENIED; + } else if (strstr(schedule_download->url, "@") != NULL) { + error = FAULT_CPE_INVALID_ARGUMENTS; + } else if (strncmp(schedule_download->url, DOWNLOAD_PROTOCOL_HTTP, strlen(DOWNLOAD_PROTOCOL_HTTP)) != 0 && strncmp(schedule_download->url, DOWNLOAD_PROTOCOL_FTP, strlen(DOWNLOAD_PROTOCOL_FTP)) != 0) { + error = FAULT_CPE_FILE_TRANSFER_UNSUPPORTED_PROTOCOL; + } else { + for (j = 0; j < 3; j++) { + if (schedule_download_delay[j] > schedule_download_delay[j + 1]) { + error = FAULT_CPE_INVALID_ARGUMENTS; + break; + } + } + } + + if (error != FAULT_CPE_NO_FAULT) + goto fault; + + t = build_top_body_soap_response(session->tree_out, "ScheduleDownload"); + + if (!t) + goto fault; + + pthread_mutex_lock(&mutex_schedule_download); + list_add_tail(&(schedule_download->list), &(list_schedule_download)); + if (schedule_download_delay[0] != 0) { + count_download_queue++; + } + while (i > 0) { + i--; + schedule_download->timewindowstruct[i].windowstart = time(NULL) + schedule_download_delay[i * 2]; + schedule_download->timewindowstruct[i].windowend = time(NULL) + schedule_download_delay[i * 2 + 1]; + } + bkp_session_insert_schedule_download(schedule_download); + bkp_session_save(); + if (schedule_download_delay[0] != 0) { + CWMP_LOG(INFO, "Schedule download will start in %us", schedule_download_delay[0]); + } else { + CWMP_LOG(INFO, "Schedule Download will start at the end of session"); + } + pthread_mutex_unlock(&mutex_schedule_download); + pthread_cond_signal(&threshold_schedule_download); + + return 0; + +fault: + cwmp_free_schedule_download_request(schedule_download); + if (cwmp_create_fault_message(session, rpc, error)) + goto error; + return 0; + +error: + return -1; +} + +/* + * [RPC CPE]: Upload + */ +int cwmp_handle_rpc_cpe_upload(struct session *session, struct rpc *rpc) +{ + mxml_node_t *n; + int error = FAULT_CPE_NO_FAULT; + struct upload *upload = NULL, *iupload; + struct list_head *ilist; + time_t scheduled_time = 0; + time_t upload_delay = 0; + char c[256]; + + if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "Upload") == -1) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + n = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); + + if (!n) + return -1; + + upload = calloc(1, sizeof(struct upload)); + if (upload == NULL) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + upload->f_instance = 0; + + struct xml_data_struct upload_xml_attrs = {0}; + upload_xml_attrs.command_key = &upload->command_key; + upload_xml_attrs.url = &upload->url; + upload_xml_attrs.username = &upload->username; + upload_xml_attrs.password = &upload->password; + upload_xml_attrs.delay_seconds = (long int*)&upload_delay; + upload_xml_attrs.file_type = &upload->file_type; + upload_xml_attrs.instance = &upload->f_instance; + + + struct xml_tag_validation upload_validation[] = {{"CommandKey", VALIDATE_STR_SIZE, 0, 32}, {"FileType", VALIDATE_STR_SIZE, 0, 64}, {"URL", VALIDATE_STR_SIZE, 0, 256}, {"Username", VALIDATE_STR_SIZE, 0, 256}, {"Password", VALIDATE_STR_SIZE, 0, 256}, {"DelaySeconds", VALIDATE_UNINT, 0, 0}}; + upload_xml_attrs.validations = upload_validation; + upload_xml_attrs.nbre_validations = 6; + + error = load_xml_node_data(SOAP_REQ_UPLOAD, n, &upload_xml_attrs); + + if (error) + goto fault; + + if (count_download_queue >= MAX_DOWNLOAD_QUEUE) { + error = FAULT_CPE_RESOURCES_EXCEEDED; + } else if (upload->url == NULL || (strcmp(upload->url, "") == 0)) { + error = FAULT_CPE_REQUEST_DENIED; + } else if (strstr(upload->url, "@") != NULL) { + error = FAULT_CPE_INVALID_ARGUMENTS; + } else if (strncmp(upload->url, DOWNLOAD_PROTOCOL_HTTPS, strlen(DOWNLOAD_PROTOCOL_HTTPS)) != 0 && strncmp(upload->url, DOWNLOAD_PROTOCOL_HTTP, strlen(DOWNLOAD_PROTOCOL_HTTP)) != 0 && strncmp(upload->url, DOWNLOAD_PROTOCOL_FTP, strlen(DOWNLOAD_PROTOCOL_FTP)) != 0) { + error = FAULT_CPE_FILE_TRANSFER_UNSUPPORTED_PROTOCOL; + } + + if (error != FAULT_CPE_NO_FAULT) { + goto fault; + } + + mxml_node_t *t = build_top_body_soap_response(session->tree_out, "Upload"); + char *start_time = "0001-01-01T00:00:00+00:00"; + char *complete_time = "0001-01-01T00:00:00+00:00"; + int status = 1; + + struct xml_data_struct upload_resp_xml_attrs = {0}; + upload_resp_xml_attrs.status = &status; + upload_resp_xml_attrs.start_time = &start_time; + upload_resp_xml_attrs.complete_time = &complete_time; + int fault = build_xml_node_data(SOAP_RESP_UPLOAD, t, &upload_resp_xml_attrs); + if (fault != CWMP_OK) { + error = FAULT_CPE_INTERNAL_ERROR; + goto fault; + } + + if (error == FAULT_CPE_NO_FAULT) { + pthread_mutex_lock(&mutex_upload); + if (upload_delay != 0) + scheduled_time = time(NULL) + upload_delay + PROCESSING_DELAY; + + list_for_each (ilist, &(list_upload)) { + iupload = list_entry(ilist, struct upload, list); + if (iupload->scheduled_time >= scheduled_time) { + break; + } + } + list_add(&(upload->list), ilist->prev); + if (upload_delay != 0) { + count_download_queue++; + upload->scheduled_time = scheduled_time; + } + bkp_session_insert_upload(upload); + bkp_session_save(); + if (upload_delay != 0) { + CWMP_LOG(INFO, "Upload will start in %us", upload_delay); + } else { + CWMP_LOG(INFO, "Upload will start at the end of session"); + } + pthread_mutex_unlock(&mutex_upload); + pthread_cond_signal(&threshold_upload); + } + return 0; + +fault: + cwmp_free_upload_request(upload); + if (cwmp_create_fault_message(session, rpc, error)) + return -1; + return 0; +} + +/* + * [FAULT]: Fault + */ + +int cwmp_handle_rpc_cpe_fault(struct session *session, struct rpc *rpc) +{ + mxml_node_t *body; + + body = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Body", NULL, NULL, MXML_DESCEND); + struct xml_data_struct fault_xml_attrs = {0}; + char *faultcode = (FAULT_CPE_ARRAY[session->fault_code].TYPE == FAULT_CPE_TYPE_CLIENT) ? "Client" : "Server"; + char *faultstring = "CWMP fault"; + int fault_code = atoi(session->fault_code ? FAULT_CPE_ARRAY[session->fault_code].CODE : "0"); + char *fault_string = strdup(FAULT_CPE_ARRAY[session->fault_code].DESCRIPTION); + fault_xml_attrs.fault_code = &fault_code; + fault_xml_attrs.fault_string = &fault_string; + fault_xml_attrs.faultcode = &faultcode; + fault_xml_attrs.faultstring = &faultstring; + + int fault = build_xml_node_data(SOAP_ROOT_FAULT, body, &fault_xml_attrs); + FREE(fault_string); + if (fault) + return -1; + + if (rpc->type == RPC_CPE_SET_PARAMETER_VALUES) { + LIST_HEAD(spv_fault_xml_data_list); + cwmp_param_fault_list_to_xml_data_list(rpc->list_set_value_fault, &spv_fault_xml_data_list); + struct xml_data_struct spv_fault_xml_attrs = {0}; + spv_fault_xml_attrs.data_list = &spv_fault_xml_data_list; + body = mxmlFindElement(session->tree_out, session->tree_out, "cwmp:Fault", NULL, NULL, MXML_DESCEND); + fault = build_xml_node_data(SOAP_SPV_FAULT, body, &spv_fault_xml_attrs); + if (fault) + return -1; + cwmp_free_all_xml_data_list(&spv_fault_xml_data_list); + } + + return 0; +} + +int cwmp_create_fault_message(struct session *session, struct rpc *rpc_cpe, int fault_code) +{ + CWMP_LOG(INFO, "Fault detected"); + session->fault_code = fault_code; + + MXML_DELETE(session->tree_out); + + if (xml_prepare_msg_out(session)) + return -1; + + CWMP_LOG(INFO, "Preparing the Fault message"); + if (rpc_cpe_methods[RPC_CPE_FAULT].handler(session, rpc_cpe)) + return -1; + rpc_cpe->type = RPC_CPE_FAULT; + + return 0; +} diff --git a/inc/rpc_soap.h b/src/rpc.h similarity index 86% rename from inc/rpc_soap.h rename to src/rpc.h index 25c4386..a63e301 100644 --- a/inc/rpc_soap.h +++ b/src/rpc.h @@ -1,13 +1,13 @@ /* - * 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. + * rpc.h - CWMP RPC methods + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2019 iopsys Software Solutions AB * Author Mohamed Kallel * Author Ahmed Zribi - * Copyright (C) 2011 Luka Perkov + * Author Omar Kallel + * + * See LICENSE file for license related information. * */ @@ -51,7 +51,6 @@ int cwmp_rpc_acs_parse_response_get_rpc_methods(struct cwmp *cwmp, struct sessio int cwmp_rpc_acs_prepare_get_rpc_methods(struct cwmp *cwmp, struct session *session, struct rpc *rpc); int cwmp_rpc_acs_prepare_transfer_complete(struct cwmp *cwmp, struct session *session, struct rpc *rpc); int cwmp_rpc_acs_prepare_du_state_change_complete(struct cwmp *cwmp, struct session *session, struct rpc *rpc); -int cwmp_rpc_acs_destroy_data_inform(struct session *session, struct rpc *rpc); int xml_handle_message(struct session *session); int cwmp_create_fault_message(struct session *session, struct rpc *rpc_cpe, int fault_code); diff --git a/sched_inform.c b/src/sched_inform.c similarity index 92% rename from sched_inform.c rename to src/sched_inform.c index a3b9033..16ea76a 100644 --- a/sched_inform.c +++ b/src/sched_inform.c @@ -1,11 +1,12 @@ /* - * 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. + * sched_inform.c - ScheduleInform method corresponding functions + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #include "sched_inform.h" diff --git a/inc/sched_inform.h b/src/sched_inform.h similarity index 57% rename from inc/sched_inform.h rename to src/sched_inform.h index dad0c0e..7d587e3 100644 --- a/inc/sched_inform.h +++ b/src/sched_inform.h @@ -1,11 +1,12 @@ /* - * 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. + * sched_inform.h - ScheduleInform method corresponding functions + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #ifndef CWMP_SCHED_INFORM_H diff --git a/session.c b/src/session.c similarity index 95% rename from session.c rename to src/session.c index 6725a42..baf5fee 100644 --- a/session.c +++ b/src/session.c @@ -1,12 +1,12 @@ /* - * 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. + * session.c - API for CWMP Session + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel * + * See LICENSE file for license related information. + * */ #include @@ -14,7 +14,7 @@ #include "session.h" #include "config.h" #include "event.h" -#include "rpc_soap.h" +#include "rpc.h" #include "backupSession.h" #include "heartbeat.h" diff --git a/inc/session.h b/src/session.h similarity index 84% rename from inc/session.h rename to src/session.h index 2bd6237..d2090c0 100644 --- a/inc/session.h +++ b/src/session.h @@ -1,18 +1,18 @@ /* - * 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. + * session.h - API for CWMP Session + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2020 iopsys Software Solutions AB * Author Omar Kallel * + * See LICENSE file for license related information. + * */ #ifndef SESSION_H_ #define SESSION_H_ -#include +#include "xml_utils.h" #include "common.h" typedef struct session { diff --git a/ssl_utils.c b/src/ssl_utils.c similarity index 100% rename from ssl_utils.c rename to src/ssl_utils.c diff --git a/inc/ssl_utils.h b/src/ssl_utils.h similarity index 100% rename from inc/ssl_utils.h rename to src/ssl_utils.h diff --git a/ubus_utils.c b/src/ubus_utils.c similarity index 100% rename from ubus_utils.c rename to src/ubus_utils.c diff --git a/inc/ubus_utils.h b/src/ubus_utils.h similarity index 72% rename from inc/ubus_utils.h rename to src/ubus_utils.h index eca1940..632b191 100644 --- a/inc/ubus_utils.h +++ b/src/ubus_utils.h @@ -1,3 +1,13 @@ +/* + * ubus_utils.h - ubus methods and utility functions + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author: suvendhu.hansa@iopsys.eu + * + * See LICENSE file for license related information + * + */ #ifndef __ICWMP_UBUS_UTILS_H__ #define __ICWMP_UBUS_UTILS_H__ diff --git a/upload.c b/src/upload.c similarity index 95% rename from upload.c rename to src/upload.c index 8c7153d..9b40a05 100644 --- a/upload.c +++ b/src/upload.c @@ -1,11 +1,12 @@ /* - * 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. + * upload.c - Upload method corresponding functions + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #include @@ -36,7 +37,7 @@ int lookup_vcf_name(int instance, char **value) CWMP_LOG(ERROR, "Not able to get the value of the parameter %s", vcf_name_parameter); return -1; } - struct cwmp_dm_parameter *param_value; + struct cwmp_dm_parameter *param_value = NULL; list_for_each_entry (param_value, &vcf_parameters, list) { *value = param_value->value ? strdup(param_value->value) : NULL; break; @@ -54,7 +55,7 @@ int lookup_vlf_name(int instance, char **value) CWMP_LOG(ERROR, "Not able to get the value of the parameter %s", vlf_name_parameter); return -1; } - struct cwmp_dm_parameter *param_value; + struct cwmp_dm_parameter *param_value = NULL; list_for_each_entry (param_value, &vlf_parameters, list) { *value = param_value->value ? strdup(param_value->value) : NULL; break; diff --git a/inc/upload.h b/src/upload.h similarity index 61% rename from inc/upload.h rename to src/upload.h index e061b78..3f05215 100644 --- a/inc/upload.h +++ b/src/upload.h @@ -1,11 +1,12 @@ /* - * 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. + * upload.h - Upload method corresponding functions + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. * - * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel + * + * See LICENSE file for license related information. + * */ #ifndef CWMP_UPLOAD_H diff --git a/src/xml.c b/src/xml.c new file mode 100644 index 0000000..2623dd9 --- /dev/null +++ b/src/xml.c @@ -0,0 +1,1434 @@ +/* + * xml.c - XML and SOAP functions + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Mohamed Kallel + * Author Ahmed Zribi + * Author Omar Kallel + * + * See LICENSE file for license related information. + * + */ + +#include "xml.h" +#include "log.h" +#include "notifications.h" +#include "http.h" +#include "cwmp_zlib.h" +#include "common.h" +#include "event.h" + +static const char *soap_env_url = "http://schemas.xmlsoap.org/soap/envelope/"; +static const char *soap_enc_url = "http://schemas.xmlsoap.org/soap/encoding/"; +static const char *xsd_url = "http://www.w3.org/2001/XMLSchema"; +static const char *xsi_url = "http://www.w3.org/2001/XMLSchema-instance"; + +const char *cwmp_urls[] = { "urn:dslforum-org:cwmp-1-0", "urn:dslforum-org:cwmp-1-1", "urn:dslforum-org:cwmp-1-2", "urn:dslforum-org:cwmp-1-2", "urn:dslforum-org:cwmp-1-2", "urn:dslforum-org:cwmp-1-2", NULL }; + +struct xml_node_data xml_nodes_data[] = { + /* + * SOAP Requests + */ + [SOAP_REQ_SPV] = {XML_SINGLE, 0, NULL, {{"ParameterList", XML_REC, SOAP_REQ_SPV_LIST, NULL}, {"ParameterKey", XML_STRING, 0, NULL}}}, + [SOAP_REQ_GPV] = {XML_LIST, SOAP_REQ_GPV_REF, "string", {}}, + [SOAP_REQ_GPN] = {XML_SINGLE, 0, NULL, {{"ParameterPath", XML_STRING, 0, NULL}, {"NextLevel", XML_BOOL, 0, NULL}}}, + [SOAP_REQ_SPA] = {XML_LIST, SOAP_REQ_SPA_REF, "SetParameterAttributesStruct", {}}, + [SOAP_REQ_GPA] = {XML_LIST, SOAP_REQ_GPA_REF, "string", {}}, + [SOAP_REQ_ADDOBJ] = {XML_SINGLE, 0, NULL, {{"ObjectName", XML_STRING, 0, NULL}, {"ParameterKey", XML_STRING, 0, NULL}}}, + [SOAP_REQ_DELOBJ] = {XML_SINGLE, 0, NULL, {{"ObjectName", XML_STRING, 0, NULL}, {"ParameterKey", XML_STRING, 0, NULL}}}, + [SOAP_REQ_REBOOT] = {XML_SINGLE, 0, NULL, {{"CommandKey", XML_STRING, 0, NULL}}}, + [SOAP_REQ_DOWNLOAD] = {XML_SINGLE, 0, NULL, {{"CommandKey", XML_STRING, 0, NULL}, {"FileType", XML_FUNC, 0, load_download_filetype}, {"URL", XML_STRING, 0, NULL}, {"Username", XML_STRING, 0, NULL}, {"Password", XML_STRING, 0, NULL}, {"FileSize", XML_INTEGER, 0, NULL}, {"DelaySeconds", XML_INTEGER, 0, NULL}}}, + [SOAP_REQ_UPLOAD] = {XML_SINGLE, 0, NULL, {{"CommandKey", XML_STRING, 0, NULL}, {"FileType", XML_FUNC, 0, load_upload_filetype}, {"URL", XML_STRING, 0, NULL}, {"Username", XML_STRING, 0, NULL}, {"Password", XML_STRING, 0, NULL}, {"DelaySeconds", XML_INTEGER, 0, NULL}}}, + [SOAP_REQ_CANCELTRANSFER] = {XML_SINGLE, 0, NULL, {{"CommandKey", XML_STRING, 0, NULL}}}, + [SOAP_REQ_SCHEDINF] = {XML_SINGLE, 0, NULL, {{"CommandKey", XML_STRING, 0, NULL}, {"DelaySeconds", XML_INTEGER, 0, NULL}}}, + [SOAP_REQ_SCHEDDOWN] = {XML_SINGLE, 0, NULL, {{"CommandKey", XML_STRING, 0, NULL}, {"FileType", XML_STRING, 0, NULL}, {"URL", XML_STRING, 0, NULL}, {"Username", XML_STRING, 0, NULL}, {"Password", XML_STRING, 0, NULL}, {"FileSize", XML_STRING, 0, NULL}, {"TimeWindowList", XML_REC, SOAP_TIMEWINDOW_REF, NULL}}}, + [SOAP_REQ_CDU] = {XML_SINGLE, 0, NULL, {{"CommandKey", XML_STRING, 0, NULL}, {"Operations", XML_REC, SOAP_REQ_CDU_OPERATIONS, NULL}}}, + [SOAP_REQ_SPV_LIST] = {XML_LIST, SOAP_REQ_SPV_LIST_REF, "ParameterValueStruct", {}}, + [SOAP_REQ_SPV_LIST_REF] = {XML_SINGLE, 0, NULL, {{"Name", XML_STRING, 0, NULL}, {"Value", XML_STRING, 0, NULL}}}, + [SOAP_REQ_GPV_REF] = {XML_SINGLE, 0, NULL, {{"string", XML_STRING, 0, NULL}}}, + [SOAP_REQ_SPA_REF] = {XML_SINGLE, 0, NULL, {{"Name", XML_STRING, 0, NULL}, {"Notification", XML_INTEGER, 0, NULL}, {"NotificationChange", XML_BOOL, 0, NULL}}}, + [SOAP_REQ_GPA_REF] = {XML_SINGLE, 0, NULL, {{"string", XML_STRING, 0, NULL}}}, + [SOAP_TIMEWINDOW_REF] = {XML_LIST, SOAP_TIME_REF, NULL, {}}, + [SOAP_TIME_REF] = {XML_SINGLE, 0, NULL, {{"WindowStart", XML_LINTEGER, 0, NULL}, {"WindowEnd", XML_LINTEGER, 0, NULL}, {"WindowMode", XML_STRING, 0, NULL}, {"WindowMode", XML_FUNC, 0, load_sched_download_window_mode}, {"MaxRetries", XML_INTEGER, 0, NULL}}}, + [SOAP_REQ_CDU_OPERATIONS] = {XML_LIST, SOAP_REQ_CDU_OPS_REF, "Operations", {}}, + [SOAP_REQ_CDU_OPS_REF] = {XML_SINGLE, 0, NULL, {{"Operations", XML_FUNC, 0, NULL}}}, + [SOAP_REQ_DU_INSTALL] = {XML_SINGLE, 0, NULL, {{"URL", XML_STRING, 0, NULL}, {"UUID", XML_STRING, 0, NULL}, {"Username", XML_STRING, 0, NULL}, {"Password", XML_STRING, 0, NULL}, {"ExecutionEnvRef", XML_STRING, 0, NULL}}}, + [SOAP_REQ_DU_UPDATE] = {XML_SINGLE, 0, NULL, {{"URL", XML_STRING, 0, NULL}, {"UUID", XML_STRING, 0, NULL}, {"Username", XML_STRING, 0, NULL}, {"Password", XML_STRING, 0, NULL}, {"Version", XML_STRING, 0, NULL}}}, + [SOAP_REQ_DU_UNINSTALL] = {XML_SINGLE, 0, NULL, {{"Version", XML_STRING, 0, NULL}, {"ExecutionEnvRef", XML_STRING, 0, NULL}, {"URL", XML_STRING, 0, NULL}}}, + + /* + * SOAP Responses + */ + [SOAP_RESP_GPV] = {XML_SINGLE, 0, NULL, {{"ParameterList", XML_NODE, ATTR_PARAM_STRUCT, NULL}}}, + [SOAP_PARAM_STRUCT] = {XML_LIST, SOAP_PARAM_STRUCT_REF, "ParameterValueStruct", {}}, + [SOAP_PARAM_STRUCT_REF] = {XML_SINGLE, 0, NULL, {{"Name", XML_STRING, 0, NULL}, {"Value", XML_STRING, ATTR_PARAM_STRUCT, NULL}}}, + [SOAP_VALUE_STRUCT] = {XML_SINGLE, 0, NULL, {{"Value", XML_STRING, ATTR_PARAM_STRUCT, NULL}}}, + [SOAP_RESP_SPV] = {XML_SINGLE, 0, NULL, {{"Status", XML_INTEGER, 0, NULL}}}, + [SOAP_RESP_GPN] = {XML_LIST, SOAP_RESP_GPN_REF, "ParameterInfoStruct", {}}, + [SOAP_RESP_GPN_REF] = {XML_SINGLE, 0, NULL, {{"Name", XML_STRING, 0, NULL}, {"Writable", XML_BOOL, 0, NULL}}}, + [SOAP_RESP_GPA] = {XML_LIST, SOAP_RESP_GPA_REF, "ParameterAttributeStruct", {}}, + [SOAP_RESP_GPA_REF] = {XML_SINGLE, 0, NULL, {{"Name", XML_STRING, 0, NULL}, {"Notification", XML_INTEGER, 0, NULL}, {"AccessList", XML_STRING, 0, NULL}}}, + [SOAP_RESP_ADDOBJ] = {XML_SINGLE, 0, NULL, {{"InstanceNumber", XML_INTEGER, 0, NULL}, {"Status", XML_INTEGER, 0, NULL}}}, + [SOAP_RESP_DELOBJ] = {XML_SINGLE, 0, NULL, {{"Status", XML_INTEGER, 0, NULL}}}, + [SOAP_RESP_DOWNLOAD] = {XML_SINGLE, 0, NULL, {{"Status", XML_INTEGER, 0, NULL}, {"StartTime", XML_STRING, 0, NULL}, {"CompleteTime", XML_STRING, 0, NULL}}}, + [SOAP_RESP_UPLOAD] = {XML_SINGLE, 0, NULL, {{"Status", XML_INTEGER, 0, NULL}, {"StartTime", XML_STRING, 0, NULL}, {"CompleteTime", XML_STRING, 0, NULL}}}, + [SOAP_RESP_GETRPC] = {XML_LIST, SOAP_RESP_GETRPC_REF, NULL, {}}, + [SOAP_RESP_GETRPC_REF] = {XML_SINGLE, 0, NULL, {{"string", XML_STRING, 0, NULL}}}, + [SOAP_ACS_TRANSCOMPLETE] = {XML_SINGLE, 0, NULL, {{"CommandKey", XML_STRING, 0, NULL}, {"FaultStruct", XML_REC, SOAP_FAULT_STRCT_REF, NULL}, {"StartTime", XML_STRING, 0, NULL}, {"CompleteTime", XML_STRING, 0, NULL}}}, + [SOAP_ROOT_FAULT] = {XML_SINGLE, 0, NULL, {{"soap_env:Fault", XML_REC, SOAP_RPC_FAULT, NULL}}}, + [SOAP_RPC_FAULT] = {XML_SINGLE, 0, NULL, {{"faultcode", XML_STRING, 0, NULL}, {"faultstring", XML_STRING, 0, NULL}, {"detail", XML_REC, SOAP_FAULT_DETAIL, NULL}}}, + [SOAP_FAULT_DETAIL] = {XML_SINGLE, 0, NULL, {{"cwmp:Fault", XML_REC, SOAP_CWMP_FAULT, NULL}}}, + [SOAP_CWMP_FAULT] = {XML_SINGLE, 0, NULL, {{"FaultCode", XML_INTEGER, 0, NULL}, {"FaultString", XML_STRING, 0, NULL}}}, + [SOAP_SPV_FAULT] = {XML_LIST, SOAP_SPV_FAULT_REF, "SetParameterValuesFault", {}}, + [SOAP_SPV_FAULT_REF] = {XML_SINGLE, 0, NULL, {{"ParameterName", XML_STRING, 0, NULL}, {"FaultCode", XML_INTEGER, 0, NULL}, {"FaultString", XML_STRING, 0, NULL}}}, + [SOAP_FAULT_STRCT_REF] = {XML_SINGLE, 0, NULL, {{"FaultCode", XML_INTEGER, 0, NULL}, {"FaultString", XML_STRING, 0, NULL}}}, + + [SOAP_ENV] = {XML_SINGLE, 0, NULL, {{"soap_env:Envelope", XML_FUNC, 0, build_inform_env_header}}}, + [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_CDU_RESULTS_REF] = {XML_LIST, 0, NULL, {{"OpResultStruct", XML_REC, SOAP_CDU_OPTS_REF, NULL}}}, + [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}}}, + [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}}} +}; + +char* xml_tags_names[] = { + "ParameterList", + "Name", + "Value", + "string", + "ParameterPath", + "ParameterName", + "ObjectName", + "ParameterKey", + "CommandKey", + "FileType", + "URL", + "Username", + "Password", + "UUID", + "ExecutionEnvRef", + "DeploymentUnitRef", + "CurrentState", + "Version", + "WindowMode", + "UserMessage", + "StartTime", + "CompleteTime", + "AccessList", + "FaultString", + "faultcode", + "faultstring", + "Manufacturer", + "OUI", + "SerialNumber", + "CurrentTime", + "ProductClass", + "xsi:type", + "FileSize", + "Notification", + "MaxRetries", + "Status", + "InstanceNumber", + "FaultCode", + "MaxEnvelopes", + "RetryCount", + "DelaySeconds", + "WindowStart", + "WindowEnd", + "NextLevel", + "NotificationChange", + "Writable", +}; + +void add_xml_data_list(struct list_head *data_list, struct xml_list_data *xml_data) +{ + list_add_tail(&xml_data->list, data_list); +} + +void delete_xml_data_from_list(struct xml_list_data *xml_data) +{ + list_del(&xml_data->list); + FREE(xml_data->param_name); + FREE(xml_data->param_value); + FREE(xml_data->param_type); + FREE(xml_data->windowmode); + FREE(xml_data->usermessage); + FREE(xml_data->access_list); + FREE(xml_data->fault_string); + FREE(xml_data->command_key); + FREE(xml_data->complete_time); + FREE(xml_data->current_state); + FREE(xml_data->execution_env_ref); + FREE(xml_data->du_ref); + FREE(xml_data->password); + FREE(xml_data->rpc_name); + FREE(xml_data->url); + FREE(xml_data->uuid); + FREE(xml_data->start_time); + FREE(xml_data->version); + FREE(xml_data); +} + +void cwmp_free_all_xml_data_list(struct list_head *list) +{ + while (list->next != list) { + struct xml_list_data *xml_data; + xml_data = list_entry(list->next, struct xml_list_data, list); + delete_xml_data_from_list(xml_data); + } +} + +int load_upload_filetype(mxml_node_t *b, struct xml_data_struct *xml_attrs) +{ + mxml_node_t *t = mxmlWalkNext(b, b, MXML_DESCEND); + const char *node_opaque = mxmlGetOpaque(t); + int error = FAULT_CPE_NO_FAULT; + char log_config[16]={0}; + int ftype, instance = 0; + + sscanf(node_opaque, "%1d Vendor %15s File %8d", &ftype, log_config, &instance); + if (strcmp(log_config, "Configuration") != 0 && strcmp(log_config, "Log") != 0) { + error = FAULT_CPE_INVALID_ARGUMENTS; + return error; + } else if (strcmp(log_config, "Configuration") == 0 && ftype != 1 && ftype != 3) { + error = FAULT_CPE_INVALID_ARGUMENTS; + return error; + } else if (strcmp(log_config, "Log") == 0 && ftype != 2 && ftype != 4) { + error = FAULT_CPE_INVALID_ARGUMENTS; + return error; + } + if ((ftype == 3 || ftype == 4) && (instance == 0)) { + error = FAULT_CPE_INVALID_ARGUMENTS; + return error; + } + if (ftype !=1 && ftype != 2 && ftype != 3 && ftype != 4) { + error = FAULT_CPE_INVALID_ARGUMENTS; + return error; + } + *xml_attrs->file_type = strdup(node_opaque); + *xml_attrs->instance = instance; + return error; +} + +int load_download_filetype(mxml_node_t *b, struct xml_data_struct *xml_attrs) +{ + int error = FAULT_CPE_NO_FAULT; + mxml_node_t *t = mxmlWalkNext(b, b, MXML_DESCEND); + const char *node_opaque = mxmlGetOpaque(t); + if (*(xml_attrs->file_type) == NULL) { + *(xml_attrs->file_type) = strdup(node_opaque); + } else { + char tmp[128]; + snprintf(tmp, sizeof(tmp), "%s", *(xml_attrs->file_type)); + FREE(*(xml_attrs->file_type)); + if (cwmp_asprintf(xml_attrs->file_type, "%s %s", tmp, node_opaque) == -1) { + error = FAULT_CPE_INTERNAL_ERROR; + return error; + } + } + return error; +} + +int load_sched_download_window_mode(mxml_node_t *b, struct xml_data_struct *xml_attrs) +{ + mxml_node_t *t = mxmlWalkNext(b, b, MXML_DESCEND); + const char *node_opaque = mxmlGetOpaque(t); + if (*(xml_attrs->window_mode) == NULL) + *(xml_attrs->window_mode) = strdup(node_opaque); + else { + static char *tmp = NULL; + tmp = *(xml_attrs->window_mode); + if (cwmp_asprintf(xml_attrs->window_mode, "%s %s", tmp, node_opaque) == -1) + return FAULT_CPE_INTERNAL_ERROR; + } + return FAULT_CPE_NO_FAULT; +} + +int load_change_du_state_operation(mxml_node_t *b, struct xml_data_struct *xml_attrs) +{ + char *operation = (char *)mxmlElementGetAttr(b, "xsi:type"); + int cdu_ref = 0; + int type = 0; + + if (strcmp(operation, "cwmp:InstallOpStruct") == 0) { + cdu_ref = SOAP_REQ_DU_INSTALL; + type = DU_INSTALL; + } + else if (strcmp(operation, "cwmp:UpdateOpStruct") == 0) { + cdu_ref = SOAP_REQ_DU_INSTALL; + type = DU_UPDATE; + } + else if (strcmp(operation, "cwmp:UninstallOpStruct") == 0) { + cdu_ref = SOAP_REQ_DU_INSTALL; + type = DU_UNINSTALL; + } + + // cppcheck-suppress autoVariables + xml_attrs->cdu_type = &type; + + if (cdu_ref == 0) + return FAULT_CPE_INVALID_ARGUMENTS; + + int fault = load_xml_node_data(cdu_ref, b, xml_attrs); + if (fault) + return fault; + + + return FAULT_CPE_NO_FAULT; +} + +int build_inform_env_header(mxml_node_t *b __attribute__((unused)), struct xml_data_struct *xml_attrs) +{ + if (b == NULL) + return FAULT_CPE_INTERNAL_ERROR; + int amd_version = xml_attrs->amd_version ? *(xml_attrs->amd_version) : 2; + mxml_node_t **envelope = xml_attrs->xml_env; + + *envelope = b; + + mxmlElementSetAttr(*envelope, "xmlns:soap_env", "http://schemas.xmlsoap.org/soap/envelope/"); + mxmlElementSetAttr(*envelope, "xmlns:soap_enc", "http://schemas.xmlsoap.org/soap/encoding/"); + mxmlElementSetAttr(*envelope, "xmlns:xsd", "http://www.w3.org/2001/XMLSchema"); + mxmlElementSetAttr(*envelope, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + mxmlElementSetAttr(*envelope, "xmlns:cwmp", cwmp_urls[amd_version - 1]); + + mxml_node_t *header = mxmlNewElement(*envelope, "soap_env:Header"); + if (header == NULL) + return FAULT_CPE_INTERNAL_ERROR; + + mxml_node_t *id = mxmlNewElement(header, "cwmp:ID"); + if (id == NULL) + return FAULT_CPE_INTERNAL_ERROR; + + mxmlElementSetAttr(id, "soap_env:mustUnderstand", "1"); + + mxml_node_t *node = NULL; + if (amd_version >= 4) { + node = mxmlNewElement(header, "cwmp:SessionTimeout"); + if (!node) + return FAULT_CPE_INTERNAL_ERROR; + + mxmlElementSetAttr(node, "soap_env:mustUnderstand", "0"); + node = mxmlNewInteger(node, *(xml_attrs->session_timeout)); + if (!node) + return FAULT_CPE_INTERNAL_ERROR; + } + + if (amd_version >= 5) { + node = mxmlNewElement(header, "cwmp:SupportedCWMPVersions"); + if (!node) + return FAULT_CPE_INTERNAL_ERROR; + + mxmlElementSetAttr(node, "soap_env:mustUnderstand", "0"); + node = mxmlNewOpaque(node, xml_get_cwmp_version(amd_version)); + if (!node) + return FAULT_CPE_INTERNAL_ERROR; + } + + mxml_node_t *body = mxmlNewElement(*envelope, "soap_env:Body"); + if (body == NULL) + return FAULT_CPE_INTERNAL_ERROR; + + return FAULT_CPE_NO_FAULT; +} + +int build_inform_events(mxml_node_t *event, struct xml_data_struct *xml_attrs) +{ + mxml_node_t *node, *b2; + char c[128]; + unsigned int n = 0; + struct cwmp *cwmp = &cwmp_main; + + cwmp->is_boot = false; + + if (!event) + return -1; + + mxmlElementSetAttr(event, "soap_enc:arrayType", "cwmp:EventStruct[0]"); + struct xml_list_data *xml_data; + + list_for_each_entry (xml_data, xml_attrs->data_list, list) { + node = mxmlNewElement(event, "EventStruct"); + if (!node) + goto error; + b2 = mxmlNewElement(node, "EventCode"); + if (!b2) + goto error; + if (xml_data->event_code == EVENT_IDX_0BOOTSTRAP || xml_data->event_code == EVENT_IDX_1BOOT) + cwmp->is_boot = true; + b2 = mxmlNewOpaque(b2, EVENT_CONST[xml_data->event_code].CODE); + if (!b2) + goto error; + b2 = mxmlNewElement(node, "CommandKey"); + if (!b2) + goto error; + if (xml_data->command_key) { + b2 = mxmlNewOpaque(b2, xml_data->command_key); + if (!b2) + goto error; + } + mxmlAdd(event, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node); + n++; + } + if (n) { + if (snprintf(c, sizeof(c), "cwmp:EventStruct[%u]", n) == -1) + return -1; + mxmlElementSetAttr(event, "xsi:type", "soap_enc:Array"); + mxmlElementSetAttr(event, "soap_enc:arrayType", c); + } + return 0; + +error: + return -1; +} + +int get_xml_type(int node_ref, int soap_idx) +{ + return xml_nodes_data[node_ref].xml_tags[soap_idx].tag_type; +} + +int get_xml_tag_index(const char *name) +{ + unsigned int i; + if (name == NULL) + return -1; + + size_t total_size = sizeof(xml_tags_names) / sizeof(char*); + for (i = 0; i < total_size; i++) { + if (strcmp(name, xml_tags_names[i]) == 0) + return i; + } + return -1; +} + + +int get_xml_soap_tag_index(int soap_ref, const char *name) +{ + unsigned int i = 0; + if (name == NULL) + return -1; + while (xml_nodes_data[soap_ref].xml_tags[i].tag_name) { + if (strcmp(name, xml_nodes_data[soap_ref].xml_tags[i].tag_name) == 0) + return i; + i++; + } + return -1; +} + +int load_xml_list_node_data(int node_ref, mxml_node_t *node, struct xml_data_struct *xml_attrs) +{ + mxml_node_t *b; + + b = mxmlWalkNext(node, node, MXML_DESCEND); + while (b) { + if (mxmlGetType(b) == MXML_ELEMENT) { + if (strcmp(xml_nodes_data[node_ref].tag_list_name, mxmlGetElement(b)) == 0) { + struct xml_list_data *xml_data = calloc(1, sizeof(struct xml_list_data)); + + struct xml_data_struct xml_attrs_args = {0}; + xml_attrs_args.name = &xml_data->param_name; + xml_attrs_args.string = &xml_data->param_name; + xml_attrs_args.parameter_path = &xml_data->param_name; + xml_attrs_args.value = &xml_data->param_value; + xml_attrs_args.window_mode = &xml_data->windowmode; + xml_attrs_args.user_message = &xml_data->usermessage; + xml_attrs_args.notification = &xml_data->notification; + xml_attrs_args.scheddown_max_retries = &xml_data->max_retries; + xml_attrs_args.window_start = &xml_data->windowstart; + xml_attrs_args.window_end = &xml_data->windowend; + xml_attrs_args.notification_change = &xml_data->notification_change; + xml_attrs_args.access_list = &xml_data->access_list; + + xml_attrs_args.url = &xml_data->url; + xml_attrs_args.uuid = &xml_data->uuid; + xml_attrs_args.username = &xml_data->username; + xml_attrs_args.password = &xml_data->password; + xml_attrs_args.exec_env_ref = &xml_data->execution_env_ref; + xml_attrs_args.version = &xml_data->version; + xml_attrs_args.cdu_type = &xml_data->cdu_type; + + xml_attrs_args.validations = xml_attrs->validations; + xml_attrs_args.nbre_validations = xml_attrs->nbre_validations; + xml_attrs_args.data_list = xml_attrs->data_list; + + list_add(&(xml_data->list), xml_attrs->data_list); + int fault = load_xml_node_data(xml_nodes_data[node_ref].tag_node_ref, b, &xml_attrs_args); + if (fault) + return fault; + } + } + b = mxmlWalkNext(b, node, MXML_DESCEND); + } + return CWMP_OK; +} + +bool validate_xml_node_opaque_value(char *node_name, char *opaque, struct xml_tag_validation *validations, int nbre_validations) +{ + int i; + for (i = 0; i < nbre_validations; i++) { + if (strcmp(node_name, validations[i].tag_name) == 0) { + if (validations[i].validation_type == VALIDATE_STR_SIZE) { + if (!icwmp_validate_string_length(opaque, validations[i].max)) + return false; + } + if (validations[i].validation_type == VALIDATE_UNINT) { + if (!icwmp_validate_unsignedint(opaque)) + return false; + } + if (validations[i].validation_type == VALIDATE_BOOLEAN) { + if (!icwmp_validate_boolean_value(opaque)) + return false; + } + if (validations[i].validation_type == VALIDATE_INT_RANGE) { + if (!icwmp_validate_int_in_range(opaque, validations[i].min, validations[i].max)) { + return false; + } + } + } + } + return true; +} + +int load_single_xml_node_data(int node_ref, mxml_node_t *node, struct xml_data_struct *xml_attrs) +{ + mxml_node_t *b = node; + int idx, xml_type = -1, soap_idx; + void **ptr = NULL; + int error = FAULT_CPE_NO_FAULT; + while (b) { + const char *node_name = mxmlGetElement(b); + mxml_type_t node_type = mxmlGetType(b); + mxml_node_t *firstchild = mxmlGetFirstChild(b); + + if (node_type == MXML_ELEMENT) { + soap_idx = get_xml_soap_tag_index(node_ref, node_name); + if (soap_idx == -1) { + b = mxmlWalkNext(b, node, MXML_DESCEND); + continue; + } + + xml_type = get_xml_type(node_ref, soap_idx); + if (xml_type == XML_FUNC) { + if ((error = xml_nodes_data[node_ref].xml_tags[soap_idx].xml_func(b, xml_attrs)) != FAULT_CPE_NO_FAULT) + return error; + b = mxmlWalkNext(b, node, MXML_DESCEND); + continue; + } + + if (xml_type == XML_REC) { + if ((error = load_xml_node_data(xml_nodes_data[node_ref].xml_tags[soap_idx].rec_ref, node, xml_attrs)) != FAULT_CPE_NO_FAULT) + return error; + b = mxmlWalkNext(b, node, MXML_DESCEND); + continue; + } + idx = get_xml_tag_index(node_name); + + // cppcheck-suppress knownConditionTrueFalse + /* + * xml_type value can be modified when calling the function get_xml_type + */ + if ((idx == -1) && (xml_type != XML_FUNC) && (xml_type != XML_REC)) { + b = mxmlWalkNext(b, node, MXML_DESCEND); + continue; + } + + char *opaque = NULL; + if (firstchild) { + opaque = (char*) mxmlGetOpaque(firstchild); + } + + if (!validate_xml_node_opaque_value((char*)mxmlGetElement(b), opaque, xml_attrs->validations, xml_attrs->nbre_validations)) + return FAULT_CPE_INVALID_ARGUMENTS; + + if ((xml_type != XML_FUNC) && (xml_type != XML_REC)) + ptr = (void **)((char *)xml_attrs + idx * sizeof(char *)); + + char **str; + int *intgr; + bool *bol; + long int *lint; + time_t *time; + + switch (xml_type) { + case XML_STRING: + str = (char **)(*ptr); + *str = strdup(opaque ? opaque : ""); + break; + case XML_INTEGER: + intgr = (int *)(*ptr); + *intgr = opaque ? atoi(opaque) : 0; + break; + case XML_BOOL: + bol = (bool *)(*ptr); + *bol = opaque && ((strcmp(opaque, "1") == 0) || (strcasecmp(opaque, "true") == 0)); + break; + case XML_LINTEGER: + lint = (long int *)(*ptr); + *lint = opaque ? atol(opaque) : 0; + break; + case XML_TIME: + time = (time_t *)(*ptr); + *time = opaque ? atol(opaque) : 0; + break; + default: + break; + } + + } + b = mxmlWalkNext(b, node, MXML_DESCEND); + } + return CWMP_OK; +} + +int load_xml_node_data(int node_ref, mxml_node_t *node, struct xml_data_struct *xml_attrs) +{ + if (node_ref >= SOAP_MAX) + return CWMP_XML_ERR; + if (xml_nodes_data[node_ref].node_ms == XML_LIST) { + return load_xml_list_node_data(node_ref, node, xml_attrs); + } else { + return load_single_xml_node_data(node_ref, node, xml_attrs); + } + return CWMP_OK; +} + +void cwmp_param_fault_list_to_xml_data_list(struct list_head *param_fault_list, struct list_head *xml_data_list) +{ + struct cwmp_param_fault *param_fault = NULL; + list_for_each_entry (param_fault, param_fault_list, list) { + if (!param_fault->fault) + continue; + + struct xml_list_data *xml_data; + + xml_data = calloc(1, sizeof(struct xml_list_data)); + list_add_tail(&xml_data->list, xml_data_list); + int idx = cwmp_get_fault_code(param_fault->fault); + xml_data->param_name = strdup(param_fault->name); + xml_data->fault_code = atoi(FAULT_CPE_ARRAY[idx].CODE); + xml_data->fault_string = strdup(FAULT_CPE_ARRAY[idx].DESCRIPTION); + } +} + +void dm_parameter_list_to_xml_data_list(struct list_head *dm_parameter_list, struct list_head *xml_data_list) +{ + struct cwmp_dm_parameter *param_value; + list_for_each_entry (param_value, dm_parameter_list, list) { + struct xml_list_data *xml_data; + + xml_data = calloc(1, sizeof(struct xml_list_data)); + list_add_tail(&xml_data->list, xml_data_list); + xml_data->param_name = strdup(param_value->name ? param_value->name : ""); + xml_data->param_value = strdup(param_value->value ? param_value->value : ""); + xml_data->param_type = strdup(param_value->type ? param_value->type : ""); + xml_data->access_list = strdup(param_value->access_list ? param_value->access_list : ""); + xml_data->notification = param_value->notification; + xml_data->writable = param_value->writable; + } +} + +void xml_data_list_to_dm_parameter_list(struct list_head *xml_data_list, struct list_head *dm_parameter_list) +{ + struct xml_list_data *xml_data; + list_for_each_entry (xml_data, xml_data_list, list) { + struct cwmp_dm_parameter *dm_parameter; + dm_parameter = calloc(1, sizeof(struct cwmp_dm_parameter)); + list_add_tail(&dm_parameter->list, dm_parameter_list); + dm_parameter->name = strdup(xml_data->param_name ? xml_data->param_name : ""); + dm_parameter->value = strdup(xml_data->param_value ? xml_data->param_value : ""); + dm_parameter->type = strdup(xml_data->param_type ? xml_data->param_type : ""); + dm_parameter->access_list = strdup(xml_data->access_list ? xml_data->access_list : ""); + dm_parameter->notification = xml_data->notification; + dm_parameter->writable =xml_data->notification; + } +} + +void xml_data_list_to_cdu_operations_list(struct list_head *xml_data_list, struct list_head *cdu_operations_list) +{ + struct xml_list_data *xml_data; + list_for_each_entry (xml_data, xml_data_list, list) { + struct operations *operation; + operation = calloc(1, sizeof(struct operations)); + list_add_tail(&operation->list, cdu_operations_list); + operation->url = strdup(xml_data->url ? xml_data->url : ""); + operation->uuid = strdup(xml_data->uuid ? xml_data->uuid : ""); + operation->username = strdup(xml_data->username ? xml_data->username : ""); + operation->password = strdup(xml_data->password ? xml_data->password : ""); + operation->executionenvref = strdup(xml_data->execution_env_ref ? xml_data->execution_env_ref : ""); + operation->version = strdup(xml_data->version ? xml_data->version : ""); + operation->type = xml_data->cdu_type; + } +} + +void cdu_operations_list_to_xml_data_list(struct list_head *du_op_list, struct list_head *xml_data_list) +{ + struct opresult *du_opt_data = NULL; + list_for_each_entry (du_opt_data, du_op_list, list) { + struct xml_list_data *xml_data = calloc(1, sizeof(struct xml_list_data)); + list_add_tail(&xml_data->list, xml_data_list); + xml_data->uuid = strdup(du_opt_data->uuid ? du_opt_data->uuid : ""); + xml_data->du_ref = strdup(du_opt_data->du_ref ? du_opt_data->du_ref : ""); + xml_data->version = strdup(du_opt_data->version ? du_opt_data->version : ""); + xml_data->current_state = strdup(du_opt_data->current_state ? du_opt_data->current_state : ""); + xml_data->start_time = strdup(du_opt_data->start_time ? du_opt_data->start_time : ""); + xml_data->complete_time = strdup(du_opt_data->complete_time ? du_opt_data->complete_time : ""); + xml_data->fault_code = du_opt_data->fault ? atoi(FAULT_CPE_ARRAY[du_opt_data->fault].CODE) : 0; + xml_data->fault_string = du_opt_data->fault ? strdup(FAULT_CPE_ARRAY[du_opt_data->fault].DESCRIPTION) : strdup(""); + } +} + +void event_container_list_to_xml_data_list(struct list_head *event_container_list, struct list_head *xml_data_list) +{ + struct event_container *event_container; + + list_for_each_entry (event_container, event_container_list, list) { + struct xml_list_data *xml_data = calloc(1, sizeof(struct xml_list_data)); + list_add_tail(&xml_data->list, xml_data_list); + xml_data->event_code = event_container->code; + xml_data->command_key = strdup(event_container->command_key); + } +} + +void get_xml_data_value_by_name(int type, int idx, struct xml_data_struct *xml_attrs, char **data_value) +{ + char **str; + int *intgr; + bool *bol; + long int *lint; + time_t *time; + + void **ptr = (void **)((char *)xml_attrs + idx * sizeof(char *)); + switch(type) { + case XML_STRING: + str = (char **)(*ptr); + *data_value = icwmp_strdup(*str ? *str : ""); + break; + case XML_INTEGER: + intgr = (int *)(*ptr); + icwmp_asprintf(data_value, "%d", *intgr); + break; + case XML_LINTEGER: + lint = (long int *)(*ptr); + icwmp_asprintf(data_value, "%ld", *lint); + break; + case XML_BOOL: + bol = (bool *)(*ptr); + *data_value = icwmp_strdup(bol ? "1" : "0"); + break; + case XML_TIME: + time = (time_t *)(*ptr); + icwmp_asprintf(data_value, "%ld", *time); + break; + case XML_NODE: + *data_value = *ptr; + break; + default: + break; + } +} + +void set_node_attributes(int attr_ref, mxml_node_t *node, struct xml_data_struct *xml_attrs) +{ + unsigned int i = 0; + size_t total_size = sizeof(xml_nodes_data[attr_ref].xml_tags) / sizeof(struct xml_tag); + + for(i =0; i < total_size; i++) { + char *attr_value = NULL; + int idx = get_xml_tag_index(xml_nodes_data[attr_ref].xml_tags[i].tag_name); + if (idx == -1) + continue; + get_xml_data_value_by_name(xml_nodes_data[attr_ref].xml_tags[i].tag_type, idx, xml_attrs, &attr_value); + if (!attr_value) + continue; + mxmlElementSetAttr(node, xml_nodes_data[attr_ref].xml_tags[i].tag_name, attr_value); + } +} + +int build_single_xml_node_data(int node_ref, mxml_node_t *node, struct xml_data_struct *xml_attrs) +{ + int i = 0, idx = 0; + mxml_node_t *n; + size_t total_size = sizeof(xml_nodes_data[node_ref].xml_tags) / sizeof(struct xml_tag); + for(i =0; i < (int)total_size; i++) { + if (xml_nodes_data[node_ref].xml_tags[i].tag_name == NULL) + continue; + + n = mxmlNewElement(node, xml_nodes_data[node_ref].xml_tags[i].tag_name); + if (!n) + return CWMP_XML_ERR; + + if (xml_nodes_data[node_ref].xml_tags[i].rec_ref >= ATTR_PARAM_STRUCT) + set_node_attributes(xml_nodes_data[node_ref].xml_tags[i].rec_ref, n, xml_attrs); + + if (xml_nodes_data[node_ref].xml_tags[i].tag_type == XML_REC) { + if (xml_nodes_data[node_ref].xml_tags[i].rec_ref > 0) + build_xml_node_data(xml_nodes_data[node_ref].xml_tags[i].rec_ref, n, xml_attrs); + continue; + } + + if (xml_nodes_data[node_ref].xml_tags[i].tag_type == XML_FUNC) { + if (xml_nodes_data[node_ref].xml_tags[i].xml_func) { + xml_nodes_data[node_ref].xml_tags[i].xml_func(n, xml_attrs); + } + continue; + } + + idx = get_xml_tag_index(xml_nodes_data[node_ref].xml_tags[i].tag_name); + if (idx == -1) + continue; + + if (xml_nodes_data[node_ref].xml_tags[i].tag_type == XML_NODE) { + mxml_node_t **t = NULL; + get_xml_data_value_by_name(xml_nodes_data[node_ref].xml_tags[i].tag_type, idx, xml_attrs, (char **)&t); + if (t != NULL) + *t = n; + continue; + } + + char *opaque = NULL; + get_xml_data_value_by_name(xml_nodes_data[node_ref].xml_tags[i].tag_type, idx, xml_attrs, &opaque); + + n = mxmlNewOpaque(n, opaque ? opaque : ""); + if (!n) + return CWMP_XML_ERR; + } + return CWMP_OK; +} + +int build_xml_list_node_data(int node_ref, mxml_node_t *node, struct xml_data_struct *xml_attrs) +{ + mxml_node_t *n; + struct xml_list_data *xml_data; + list_for_each_entry (xml_data, xml_attrs->data_list, list) { + if (xml_nodes_data[node_ref].tag_list_name) { + n = mxmlNewElement(node, xml_nodes_data[node_ref].tag_list_name); + if (!n) + return CWMP_XML_ERR; + } else { + n = node; + } + if (xml_nodes_data[node_ref].tag_node_ref > 0) { + struct xml_data_struct xml_ref_data = {0}; + xml_ref_data.name = &xml_data->param_name; + xml_ref_data.parameter_name = &xml_data->param_name; + xml_ref_data.value = &xml_data->param_value; + xml_ref_data.string = &xml_data->rpc_name; + xml_ref_data.xsi_type = &xml_data->param_type; + xml_ref_data.notification = &xml_data->notification; + xml_ref_data.writable = &xml_data->writable; + xml_ref_data.access_list = &xml_data->access_list; + xml_ref_data.fault_string = &xml_data->fault_string; + xml_ref_data.fault_code = &xml_data->fault_code; + xml_ref_data.current_state = &xml_data->current_state; + xml_ref_data.du_ref = &xml_data->du_ref; + + int fault = build_xml_node_data(xml_nodes_data[node_ref].tag_node_ref, n, &xml_ref_data); + + if (fault != CWMP_OK) + return fault; + } + if (xml_attrs->counter != NULL) + *(xml_attrs->counter)+=1; + } + return 0; +} + +int build_xml_node_data(int node_ref, mxml_node_t *node, struct xml_data_struct *xml_attrs) +{ + if (node_ref >= SOAP_MAX) + return CWMP_XML_ERR; + + if (xml_nodes_data[node_ref].node_ms == XML_LIST ) { + return build_xml_list_node_data(node_ref, node, xml_attrs); + } else + return build_single_xml_node_data(node_ref, node, xml_attrs); + return CWMP_OK; +} + +mxml_node_t * build_top_body_soap_response(mxml_node_t *node, char *method) +{ + mxml_node_t *n = mxmlFindElement(node, node, "soap_env:Body", NULL, NULL, MXML_DESCEND); + + if (!n) + return NULL; + + char method_resp[128]; + snprintf(method_resp, sizeof(method_resp), "cwmp:%sResponse", method); + n = mxmlNewElement(n, method_resp); + + if (!n) + return NULL; + + return n; +} + +mxml_node_t * build_top_body_soap_request(mxml_node_t *node, char *method) +{ + mxml_node_t *n = mxmlFindElement(node, node, "soap_env:Body", NULL, NULL, MXML_DESCEND); + + if (!n) + return NULL; + + char method_resp[128]; + snprintf(method_resp, sizeof(method_resp), "cwmp:%s", method); + n = mxmlNewElement(n, method_resp); + + if (!n) + return NULL; + + return n; +} + +mxml_node_t * /* O - Element node or NULL */ +mxmlFindElementOpaque(mxml_node_t *node, /* I - Current node */ + mxml_node_t *top, /* I - Top node */ + const char *text, /* I - Element text, if NULL return NULL */ + int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ +{ + if (!node || !top || !text) + return (NULL); + + node = mxmlWalkNext(node, top, descend); + + while (node != NULL) { + const char *op = mxmlGetOpaque(node); + if (mxmlGetType(node) == MXML_OPAQUE && op && (!strcmp(op, text))) { + return (node); + } + + if (descend == MXML_DESCEND) + node = mxmlWalkNext(node, top, MXML_DESCEND); + else + node = mxmlGetNextSibling(node); + } + return (NULL); +} + +char *xml__get_attribute_name_by_value(mxml_node_t *node, const char *value) +{ + int attributes_nbre = mxmlElementGetAttrCount(node); + int i; + for (i = 0; i < attributes_nbre; i++) { + char *attr_name = NULL; + const char *attr_value = mxmlElementGetAttrByIndex(node, i, (const char **)&attr_name); + if (strcmp(attr_value, value) == 0) + return attr_name; + } + return NULL; +} + +int xml_recreate_namespace(mxml_node_t *tree) +{ + const char *cwmp_urn; + int i; + mxml_node_t *b = tree; + + do { + char *c; + FREE(ns.soap_env); + FREE(ns.soap_enc); + FREE(ns.xsd); + FREE(ns.xsi); + FREE(ns.cwmp); + + c = (char *)xml__get_attribute_name_by_value(b, soap_env_url); + if (c && *(c + 5) == ':') { + ns.soap_env = strdup((c + 6)); + } else { + continue; + } + + c = (char *)xml__get_attribute_name_by_value(b, soap_enc_url); + if (c && *(c + 5) == ':') { + ns.soap_enc = strdup((c + 6)); + } else { + continue; + } + + c = (char *)xml__get_attribute_name_by_value(b, xsd_url); + if (c && *(c + 5) == ':') { + ns.xsd = strdup((c + 6)); + } else { + continue; + } + + c = (char *)xml__get_attribute_name_by_value(b, xsi_url); + if (c && *(c + 5) == ':') { + ns.xsi = strdup((c + 6)); + } else { + continue; + } + + for (i = 0; cwmp_urls[i] != NULL; i++) { + cwmp_urn = cwmp_urls[i]; + c = (char *)xml__get_attribute_name_by_value(b, cwmp_urn); + if (c && *(c + 5) == ':') { + ns.cwmp = strdup((c + 6)); + break; + } + } + + if (!ns.cwmp) + continue; + + return 0; + } while ((b = mxmlWalkNext(b, tree, MXML_DESCEND))); + + return -1; +} + +void xml_exit(void) +{ + FREE(ns.soap_env); + FREE(ns.soap_enc); + FREE(ns.xsd); + FREE(ns.xsi); + FREE(ns.cwmp); +} + +int xml_send_message(struct cwmp *cwmp, struct session *session, struct rpc *rpc) +{ + char *s, *msg_out = NULL, *msg_in = NULL; + char c[512]; + int msg_out_len = 0, f, r = 0; + mxml_node_t *b; + + if (session->tree_out) { + unsigned char *zmsg_out; + msg_out = mxmlSaveAllocString(session->tree_out, whitespace_cb); + CWMP_LOG_XML_MSG(DEBUG, msg_out, XML_MSG_OUT); + if (cwmp->conf.compression != COMP_NONE) { + if (zlib_compress(msg_out, &zmsg_out, &msg_out_len, cwmp->conf.compression)) { + return -1; + } + FREE(msg_out); + msg_out = (char *)zmsg_out; + } else { + msg_out_len = strlen(msg_out); + } + } + while (1) { + f = 0; + if (icwmp_http_send_message(cwmp, msg_out, msg_out_len, &msg_in)) { + goto error; + } + if (msg_in) { + CWMP_LOG_XML_MSG(DEBUG, msg_in, XML_MSG_IN); + if ((s = strstr(msg_in, ""))) + sscanf(s, "%d", &f); + if (f) { + if (f == 8005) { + r++; + if (r < 5) { + FREE(msg_in); + continue; + } + goto error; + } else if (rpc && rpc->type != RPC_ACS_INFORM) { + break; + } else { + goto error; + } + } else { + break; + } + } else { + goto end; + } + } + + session->tree_in = mxmlLoadString(NULL, msg_in, MXML_OPAQUE_CALLBACK); + if (!session->tree_in) + goto error; + xml_recreate_namespace(session->tree_in); + /* get NoMoreRequests or HolRequest*/ + session->hold_request = false; + + if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "NoMoreRequests") == -1) + goto error; + b = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); + if (b) { + b = mxmlWalkNext(b, session->tree_in, MXML_DESCEND_FIRST); + if (b && mxmlGetType(b) == MXML_OPAQUE && mxmlGetOpaque(b)) + session->hold_request = atoi(mxmlGetOpaque(b)); + } else { + if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "HoldRequests") == -1) + goto error; + + b = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); + if (b) { + b = mxmlWalkNext(b, session->tree_in, MXML_DESCEND_FIRST); + if (b && mxmlGetType(b) == MXML_OPAQUE && mxmlGetOpaque(b)) + session->hold_request = atoi(mxmlGetOpaque(b)); + } + } + +end: + FREE(msg_out); + FREE(msg_in); + return 0; + +error: + FREE(msg_out); + FREE(msg_in); + return -1; +} + +int xml_prepare_msg_out(struct session *session) +{ + struct cwmp *cwmp = &cwmp_main; + struct config *conf; + conf = &(cwmp->conf); + mxml_node_t *n; + + load_response_xml_schema(&session->tree_out); + if (!session->tree_out) + return -1; + + n = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Envelope", NULL, NULL, MXML_DESCEND); + if (!n) { + return -1; + } + + mxmlElementSetAttr(n, "xmlns:cwmp", cwmp_urls[(conf->amd_version) - 1]); + if (!session->tree_out) + return -1; + + return 0; +} + +int xml_set_cwmp_id(struct session *session) +{ + char c[32]; + mxml_node_t *b; + + /* define cwmp id */ + if (snprintf(c, sizeof(c), "%u", ++(cwmp_main.cwmp_id)) == -1) + return -1; + + b = mxmlFindElement(session->tree_out, session->tree_out, "cwmp:ID", NULL, NULL, MXML_DESCEND); + if (!b) + return -1; + + b = mxmlNewOpaque(b, c); + if (!b) + return -1; + + return 0; +} + +int xml_set_cwmp_id_rpc_cpe(struct session *session) +{ + char c[512]; + mxml_node_t *b; + + /* handle cwmp:ID */ + if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "ID") == -1) + return -1; + + b = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); + + if (b) { + /* ACS send ID parameter */ + b = mxmlWalkNext(b, session->tree_in, MXML_DESCEND_FIRST); + if (!b || mxmlGetType(b) != MXML_OPAQUE || !mxmlGetOpaque(b)) + return 0; + snprintf(c, sizeof(c), "%s", mxmlGetOpaque(b)); + + b = mxmlFindElement(session->tree_out, session->tree_out, "cwmp:ID", NULL, NULL, MXML_DESCEND); + if (!b) + return -1; + + b = mxmlNewOpaque(b, c); + if (!b) + return -1; + } else { + /* ACS does not send ID parameter */ + int r = xml_set_cwmp_id(session); + return r; + } + return 0; +} + +const char *get_node_tab_space(mxml_node_t *node) +{ + static char tab_space[10 * sizeof(CWMP_MXML_TAB_SPACE) + 1]; + int count = 0; + + memset(tab_space, 0, sizeof(tab_space)); + while ((node = mxmlGetParent(node))) { + count = count + 1; + } + + if (count) { + snprintf(tab_space, sizeof(tab_space), "%*s", (int)(count * sizeof(CWMP_MXML_TAB_SPACE)), ""); + } + + return tab_space; +} + +const char *whitespace_cb(mxml_node_t *node, int where __attribute__((unused))) +{ + if (mxmlGetType(node) != MXML_ELEMENT) + return NULL; + + switch (where) { + case MXML_WS_BEFORE_CLOSE: + if (mxmlGetFirstChild(node) && mxmlGetType(mxmlGetFirstChild(node)) != MXML_ELEMENT) + return NULL; + + return get_node_tab_space(node); + case MXML_WS_BEFORE_OPEN: + if (where == MXML_WS_BEFORE_CLOSE && mxmlGetFirstChild(node) && mxmlGetType(mxmlGetFirstChild(node)) != MXML_ELEMENT) + return NULL; + + return get_node_tab_space(node); + case MXML_WS_AFTER_OPEN: + return ((mxmlGetFirstChild(node) == NULL || mxmlGetType(mxmlGetFirstChild(node)) == MXML_ELEMENT) ? "\n" : NULL); + case MXML_WS_AFTER_CLOSE: + return "\n"; + default: + return NULL; + } + + return NULL; +} + +char *xml_get_cwmp_version(int version) +{ + static char versions[60]; + unsigned pos = 0; + int k; + + versions[0] = '\0'; + for (k = 0; k < version; k++) { + pos += snprintf(&versions[pos], sizeof(versions) - pos, "1.%d, ", k); + } + + if (pos) + versions[pos - 2] = 0; + + return versions; +} + +static int xml_prepare_lwnotifications(mxml_node_t *parameter_list) +{ + mxml_node_t *b, *n; + + struct list_head *p; + struct cwmp_dm_parameter *lw_notification; + list_for_each (p, &list_lw_value_change) { + lw_notification = list_entry(p, struct cwmp_dm_parameter, list); + + n = mxmlNewElement(parameter_list, "Param"); + if (!n) + goto error; + + b = mxmlNewElement(n, "Name"); + if (!b) + goto error; + + b = mxmlNewOpaque(b, lw_notification->name); + if (!b) + goto error; + + b = mxmlNewElement(n, "Value"); + if (!b) + goto error; + mxmlElementSetAttr(b, "xsi:type", lw_notification->type); + b = mxmlNewOpaque(b, lw_notification->value); + if (!b) + goto error; + } + return 0; + +error: + return -1; +} + +int xml_prepare_lwnotification_message(char **msg_out) +{ + mxml_node_t *lw_tree; + + load_notification_xml_schema(&lw_tree); + if (!lw_tree) + goto error; + + *msg_out = mxmlSaveAllocString(lw_tree, whitespace_cb); + + mxmlDelete(lw_tree); + return 0; + +error: + return -1; +} + +void load_notification_xml_schema(mxml_node_t **tree) +{ + char declaration[1024] = {0}; + struct cwmp *cwmp = &cwmp_main; + struct config *conf; + conf = &(cwmp->conf); + char *c = NULL; + + if (tree == NULL) + return; + + *tree = NULL; + + snprintf(declaration, sizeof(declaration), "?xml version=\"1.0\" encoding=\"UTF-8\"?"); + mxml_node_t *xml = mxmlNewElement(NULL, declaration); + if (xml == NULL) + return; + + mxml_node_t *notification = mxmlNewElement(xml, "Notification"); + if (notification == NULL) { + MXML_DELETE(xml); + return; + } + + mxmlElementSetAttr(notification, "xmlns", "urn:broadband-forum-org:cwmp:lwnotif-1-0"); + mxmlElementSetAttr(notification, "xmlns:xs", xsd_url); + mxmlElementSetAttr(notification, "xmlns:xsi", xsi_url); + mxmlElementSetAttr(notification, "xsi:schemaLocation", "urn:broadband-forum-org:cwmp:lxnotif-1-0 http://www.broadband-forum.org/cwmp/cwmp-UDPLightweightNotification-1-0.xsd"); + + mxml_node_t *ts = mxmlNewElement(notification, "TS"); + if (ts == NULL) { + MXML_DELETE(xml); + return; + } + + if (cwmp_asprintf(&c, "%ld", time(NULL)) == -1) { + MXML_DELETE(xml); + return; + } + + if (NULL == mxmlNewOpaque(ts, c)) { + FREE(c); + MXML_DELETE(xml); + return; + } + + FREE(c); + + mxml_node_t *un = mxmlNewElement(notification, "UN"); + if (un == NULL) { + MXML_DELETE(xml); + return; + } + + if (NULL == mxmlNewOpaque(un, conf->acs_userid)) { + MXML_DELETE(xml); + return; + } + + mxml_node_t *cn = mxmlNewElement(notification, "CN"); + if (cn == NULL) { + MXML_DELETE(xml); + return; + } + + c = (char *)calculate_lwnotification_cnonce(); + if (!c) { + MXML_DELETE(xml); + return; + } + + if (NULL == mxmlNewOpaque(cn, c)) { + FREE(c); + MXML_DELETE(xml); + return; + } + + FREE(c); + + mxml_node_t *oui = mxmlNewElement(notification, "OUI"); + if (oui == NULL) { + MXML_DELETE(xml); + return; + } + + if (NULL == mxmlNewOpaque(oui, cwmp->deviceid.oui)) { + MXML_DELETE(xml); + return; + } + + mxml_node_t *pclass = mxmlNewElement(notification, "ProductClass"); + if (pclass == NULL) { + MXML_DELETE(xml); + return; + } + + if (NULL == mxmlNewOpaque(pclass, cwmp->deviceid.productclass ? cwmp->deviceid.productclass : "")) { + MXML_DELETE(xml); + return; + } + + mxml_node_t *slno = mxmlNewElement(notification, "SerialNumber"); + if (slno == NULL) { + MXML_DELETE(xml); + return; + } + + if (NULL == mxmlNewOpaque(slno, cwmp->deviceid.serialnumber ? cwmp->deviceid.serialnumber : "")) { + MXML_DELETE(xml); + return; + } + + if (xml_prepare_lwnotifications(notification)) { + MXML_DELETE(xml); + return; + } + + *tree = xml; +} + +void load_response_xml_schema(mxml_node_t **schema) +{ + char declaration[1024] = {0}; + + if (schema == NULL) + return; + + *schema = NULL; + + snprintf(declaration, sizeof(declaration), "?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?"); + mxml_node_t *xml = mxmlNewElement(NULL, declaration); + if (xml == NULL) + return; + + mxml_node_t *envlp = mxmlNewElement(xml, "soap_env:Envelope"); + if (envlp == NULL) { + MXML_DELETE(xml); + return; + } + + mxmlElementSetAttr(envlp, "xmlns:soap_env", soap_env_url); + mxmlElementSetAttr(envlp, "xmlns:soap_enc", soap_enc_url); + mxmlElementSetAttr(envlp, "xmlns:xsd", xsd_url); + mxmlElementSetAttr(envlp, "xmlns:xsi", xsi_url); + + mxml_node_t *header = mxmlNewElement(envlp, "soap_env:Header"); + if (header == NULL) { + MXML_DELETE(xml); + return; + } + + mxml_node_t *id = mxmlNewElement(header, "cwmp:ID"); + if (id == NULL) { + MXML_DELETE(xml); + return; + } + + mxmlElementSetAttr(id, "soap_env:mustUnderstand", "1"); + + if (NULL == mxmlNewElement(envlp, "soap_env:Body")) { + MXML_DELETE(xml); + return; + } + + *schema = xml; +} diff --git a/src/xml.h b/src/xml.h new file mode 100644 index 0000000..7d2c134 --- /dev/null +++ b/src/xml.h @@ -0,0 +1,255 @@ +#ifndef __XML__H_ +#define __XML__H_ + +#include "xml_utils.h" +#include "session.h" +#include "common.h" + +#define CWMP_MXML_TAB_SPACE " " +#define MAX_SCHEDULE_INFORM_QUEUE 10 + +#define XML2(A,B) {A, B, 0, NULL} +#define XML3(A,B,C) {A, B, C, NULL} +#define XML4(A,B,D) {A, B, 0, D} +enum soap_methods { + SOAP_REQ_SPV = 1, + SOAP_REQ_GPV, + SOAP_REQ_GPN, + SOAP_REQ_SPA, + SOAP_REQ_GPA, + SOAP_REQ_ADDOBJ, + SOAP_REQ_DELOBJ, + SOAP_REQ_REBOOT, + SOAP_REQ_DOWNLOAD, + SOAP_REQ_UPLOAD, + SOAP_REQ_CANCELTRANSFER, + SOAP_REQ_SCHEDINF, + SOAP_REQ_SCHEDDOWN, + SOAP_REQ_CDU, + SOAP_REQ_SPV_LIST, + SOAP_REQ_SPV_LIST_REF, + SOAP_REQ_GPV_REF, + SOAP_REQ_SPA_REF, + SOAP_REQ_GPA_REF, + SOAP_TIMEWINDOW_REF, + SOAP_TIME_REF, + SOAP_REQ_CDU_OPERATIONS, + SOAP_REQ_CDU_OPS_REF, + SOAP_REQ_DU_INSTALL, + SOAP_REQ_DU_UPDATE, + SOAP_REQ_DU_UNINSTALL, + + SOAP_RESP_GPV, + SOAP_PARAM_STRUCT, + SOAP_PARAM_STRUCT_REF, + SOAP_VALUE_STRUCT, + SOAP_RESP_SPV, + SOAP_RESP_GPN, + SOAP_RESP_GPN_REF, + SOAP_RESP_GPA, + SOAP_RESP_GPA_REF, + SOAP_RESP_ADDOBJ, + SOAP_RESP_DELOBJ, + SOAP_RESP_DOWNLOAD, + SOAP_RESP_UPLOAD, + SOAP_RESP_GETRPC, + SOAP_RESP_GETRPC_REF, + SOAP_ACS_TRANSCOMPLETE, + SOAP_ROOT_FAULT, + SOAP_RPC_FAULT, + SOAP_FAULT_DETAIL, + SOAP_CWMP_FAULT, + SOAP_SPV_FAULT, + SOAP_SPV_FAULT_REF, + SOAP_FAULT_STRCT_REF, + SOAP_ENV, + SOAP_HEAD, + SOAP_BODY, + SOAP_INFORM_CWMP, + SOAP_DEVID, + SOAP_DU_CHANGE_COMPLETE, + SOAP_CDU_RESULTS_REF, + SOAP_CDU_OPTS_REF, + ATTR_PARAM_STRUCT, + ATTR_SOAP_ENV, + SOAP_MAX +}; + +enum xml_tag_types { + XML_STRING, + XML_BOOL, + XML_INTEGER, + XML_LINTEGER, + XML_TIME, + XML_FUNC, + XML_REC, + XML_NODE, + XML_ATTR +}; + +enum tag_multiple_single { + XML_SINGLE, + XML_LIST +}; + +enum validation_types { + VALIDATE_STR_SIZE, + VALIDATE_UNINT, + VALIDATE_BOOLEAN, + VALIDATE_INT_RANGE +}; + +struct xml_tag_validation { + char *tag_name; + int validation_type; + int min; + int max; +}; + +struct xml_data_struct { + mxml_node_t **parameter_list; + char **name; + char **value; + char **string; + char **parameter_path; + char **parameter_name; + char **object_name; + char **parameter_key; + char **command_key; + char **file_type; + char **url; + char **username; + char **password; + char **uuid; + char **exec_env_ref; + char **du_ref; + char **current_state; + char **version; + char **window_mode; + char **user_message; + char **start_time; + char **complete_time; + char **access_list; + char **fault_string; + char **faultcode; + char **faultstring; + char **manufacturer; + char **oui; + char **serial_number; + char **current_time; + char **product_class; + char **xsi_type; + int *file_size; + int *notification; + int *scheddown_max_retries; + int *status; + int *instance; + int *fault_code; + int *max_envelopes; + int *retry_count; + long int *delay_seconds; + long int *window_start; + long int *window_end; + bool *next_level; + bool *notification_change; + bool *writable; + + mxml_node_t **xml_env; + struct list_head *data_list; + char **xcwmp; + int *amd_version; + unsigned int *session_timeout; + int *cdu_type; + int *counter; + struct xml_tag_validation *validations; + int nbre_validations; +}; + +struct xml_list_data { + struct list_head list; + char *param_name; + char *param_value; + char *param_type; + char *windowmode; + char *usermessage; + char *access_list; + char *rpc_name; + char *fault_string; + char *url; + char *uuid; + char *username; + char *password; + char *execution_env_ref; + char *version; + char *du_ref; + char *current_state; + char *start_time; + char *complete_time; + char *command_key; + + long int windowstart; + long int windowend; + int max_retries; + int notification; + int fault_code; + int cdu_type; + int event_code; + bool notification_change; + bool writable; +}; + +struct xml_tag { + char *tag_name; + int tag_type; + int rec_ref; + int (*xml_func)(mxml_node_t *node, struct xml_data_struct *xml_attrs); +}; + +struct xml_node_data { + int node_ms; + int tag_node_ref; + char *tag_list_name; + struct xml_tag xml_tags[10]; +}; + +#define MXML_DELETE(X) \ + do { \ + if (X) { \ + mxmlDelete(X); \ + X = NULL; \ + } \ + } while (0) + +extern const char *cwmp_urls[]; +int xml_prepare_msg_out(struct session *session); +int xml_prepare_lwnotification_message(char **msg_out); +int xml_set_cwmp_id_rpc_cpe(struct session *session); +int xml_recreate_namespace(mxml_node_t *tree); +const char *whitespace_cb(mxml_node_t *node, int where); +int xml_set_cwmp_id(struct session *session); +int xml_send_message(struct cwmp *cwmp, struct session *session, struct rpc *rpc); +mxml_node_t *mxmlFindElementOpaque(mxml_node_t *node, mxml_node_t *top, const char *text, int descend); +char *xml__get_attribute_name_by_value(mxml_node_t *node, const char *value); +char *xml_get_cwmp_version(int version); +void xml_exit(void); +void load_response_xml_schema(mxml_node_t **schema); +void load_notification_xml_schema(mxml_node_t **tree); +int load_xml_node_data(int node_ref, mxml_node_t *node, struct xml_data_struct *xml_attrs); +int build_xml_node_data(int node_ref, mxml_node_t *node, struct xml_data_struct *xml_attrs); +void add_xml_data_list(struct list_head *data_list, struct xml_list_data *xml_data); +mxml_node_t * build_top_body_soap_response(mxml_node_t *node, char *method); +mxml_node_t * build_top_body_soap_request(mxml_node_t *node, char *method); +void dm_parameter_list_to_xml_data_list(struct list_head *dm_parameter_list, struct list_head *xml_data_list); +void xml_data_list_to_dm_parameter_list(struct list_head *xml_data_list, struct list_head *dm_parameter_list); +void xml_data_list_to_cdu_operations_list(struct list_head *xml_data_list, struct list_head *du_op_list); +void cdu_operations_list_to_xml_data_list(struct list_head *du_op_list, struct list_head *xml_data_list); +void event_container_list_to_xml_data_list(struct list_head *event_container, struct list_head *xml_data_list); +void cwmp_param_fault_list_to_xml_data_list(struct list_head *param_fault_list, struct list_head *xml_data_list); +void cwmp_free_all_xml_data_list(struct list_head *list); +int load_upload_filetype(mxml_node_t *b, struct xml_data_struct *xml_attrs); +int load_download_filetype(mxml_node_t *b, struct xml_data_struct *xml_attrs); +int load_sched_download_window_mode(mxml_node_t *b, struct xml_data_struct *xml_attrs); +int load_change_du_state_operation(mxml_node_t *b, struct xml_data_struct *xml_attrs); +int build_inform_events(mxml_node_t *b, struct xml_data_struct *xml_attrs); +int build_inform_env_header(mxml_node_t *b, struct xml_data_struct *xml_attrs); +#endif diff --git a/inc/xml_utils.h b/src/xml_utils.h similarity index 100% rename from inc/xml_utils.h rename to src/xml_utils.h diff --git a/test/cmocka/Makefile b/test/cmocka/Makefile index 2c4a809..2537146 100644 --- a/test/cmocka/Makefile +++ b/test/cmocka/Makefile @@ -4,20 +4,20 @@ LIB_LDFLAGS:= -luci -lblobmsg_json -lubox\ -ljson-c -lubus -lpthread -lcurl\ -lcrypto -lmxml -LIB_CFLAGS:= -fPIC -I../../inc -DLOPENSSL -g -O0 +LIB_CFLAGS:= -fPIC -I../../src/ -DLOPENSSL -g -O0 UNIT_TESTS:= icwmp_unit_testd VALGRIND = /usr/bin/valgrind --xml=yes --xml-file=memory-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all - -ICWMP_SOURCES=$(patsubst ./%.c, ../../%.c, $(icwmpd_SOURCES)) -ICWMP_OBJS=$(patsubst ../../%.c, %.o, $(ICWMP_SOURCES)) + +ICWMP_SOURCES=$(patsubst ./src/%.c, ../../src/%.c, $(icwmpd_SOURCES)) +ICWMP_OBJS=$(patsubst ../../src/%.c, %.o, $(ICWMP_SOURCES)) TEST_SRCS = $(wildcard *.c) TEST_OBJS = $(TEST_SRCS:=.o) %.c.o: %.c - $(CC) -g -O0 -I../../inc -c -o $@ $< + $(CC) -g -O0 -I../../src/ -c -o $@ $< -%.o: ../../%.c +%.o: ../../src/%.c $(CC) ${LIB_CFLAGS} -c -o $@ $< libunit: ${ICWMP_OBJS} diff --git a/test/cmocka/icwmp_custom_inform_parameters_unit_test.c b/test/cmocka/icwmp_custom_inform_parameters_unit_test.c index 8293eda..0d04503 100644 --- a/test/cmocka/icwmp_custom_inform_parameters_unit_test.c +++ b/test/cmocka/icwmp_custom_inform_parameters_unit_test.c @@ -18,7 +18,7 @@ #include "common.h" #include "config.h" -#include "rpc_soap.h" +#include "rpc.h" static struct cwmp cwmp_main_test = { 0 }; diff --git a/test/cmocka/icwmp_datamodel_interface_unit_test.c b/test/cmocka/icwmp_datamodel_interface_unit_test.c index 057fc68..d4009f6 100644 --- a/test/cmocka/icwmp_datamodel_interface_unit_test.c +++ b/test/cmocka/icwmp_datamodel_interface_unit_test.c @@ -19,7 +19,7 @@ #include "datamodel_interface.h" #include "event.h" #include "xml.h" -#include "rpc_soap.h" +#include "rpc.h" #include "session.h" #include "log.h" diff --git a/test/cmocka/icwmp_soap_msg_unit_test.c b/test/cmocka/icwmp_soap_msg_unit_test.c index ec225b2..3e0faad 100644 --- a/test/cmocka/icwmp_soap_msg_unit_test.c +++ b/test/cmocka/icwmp_soap_msg_unit_test.c @@ -16,7 +16,7 @@ #include #include -#include "rpc_soap.h" +#include "rpc.h" #include "event.h" #include "session.h" #include "config.h" diff --git a/xml.c b/xml.c deleted file mode 100644 index 2091036..0000000 --- a/xml.c +++ /dev/null @@ -1,577 +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 - */ - -#include "xml.h" -#include "log.h" -#include "notifications.h" -#include "http.h" -#include "cwmp_zlib.h" - -static const char *soap_env_url = "http://schemas.xmlsoap.org/soap/envelope/"; -static const char *soap_enc_url = "http://schemas.xmlsoap.org/soap/encoding/"; -static const char *xsd_url = "http://www.w3.org/2001/XMLSchema"; -static const char *xsi_url = "http://www.w3.org/2001/XMLSchema-instance"; - -const char *cwmp_urls[] = { "urn:dslforum-org:cwmp-1-0", "urn:dslforum-org:cwmp-1-1", "urn:dslforum-org:cwmp-1-2", "urn:dslforum-org:cwmp-1-2", "urn:dslforum-org:cwmp-1-2", "urn:dslforum-org:cwmp-1-2", NULL }; - -mxml_node_t * /* O - Element node or NULL */ -mxmlFindElementOpaque(mxml_node_t *node, /* I - Current node */ - mxml_node_t *top, /* I - Top node */ - const char *text, /* I - Element text, if NULL return NULL */ - int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ -{ - if (!node || !top || !text) - return (NULL); - - node = mxmlWalkNext(node, top, descend); - - while (node != NULL) { - const char *op = mxmlGetOpaque(node); - if (mxmlGetType(node) == MXML_OPAQUE && op && (!strcmp(op, text))) { - return (node); - } - - if (descend == MXML_DESCEND) - node = mxmlWalkNext(node, top, MXML_DESCEND); - else - node = mxmlGetNextSibling(node); - } - return (NULL); -} - -char *xml__get_attribute_name_by_value(mxml_node_t *node, const char *value) -{ - int attributes_nbre = mxmlElementGetAttrCount(node); - int i; - for (i = 0; i < attributes_nbre; i++) { - char *attr_name = NULL; - const char *attr_value = mxmlElementGetAttrByIndex(node, i, (const char **)&attr_name); - if (strcmp(attr_value, value) == 0) - return attr_name; - } - return NULL; -} - -int xml_recreate_namespace(mxml_node_t *tree) -{ - const char *cwmp_urn; - int i; - mxml_node_t *b = tree; - - do { - char *c; - FREE(ns.soap_env); - FREE(ns.soap_enc); - FREE(ns.xsd); - FREE(ns.xsi); - FREE(ns.cwmp); - - c = (char *)xml__get_attribute_name_by_value(b, soap_env_url); - if (c && *(c + 5) == ':') { - ns.soap_env = strdup((c + 6)); - } else { - continue; - } - - c = (char *)xml__get_attribute_name_by_value(b, soap_enc_url); - if (c && *(c + 5) == ':') { - ns.soap_enc = strdup((c + 6)); - } else { - continue; - } - - c = (char *)xml__get_attribute_name_by_value(b, xsd_url); - if (c && *(c + 5) == ':') { - ns.xsd = strdup((c + 6)); - } else { - continue; - } - - c = (char *)xml__get_attribute_name_by_value(b, xsi_url); - if (c && *(c + 5) == ':') { - ns.xsi = strdup((c + 6)); - } else { - continue; - } - - for (i = 0; cwmp_urls[i] != NULL; i++) { - cwmp_urn = cwmp_urls[i]; - c = (char *)xml__get_attribute_name_by_value(b, cwmp_urn); - if (c && *(c + 5) == ':') { - ns.cwmp = strdup((c + 6)); - break; - } - } - - if (!ns.cwmp) - continue; - - return 0; - } while ((b = mxmlWalkNext(b, tree, MXML_DESCEND))); - - return -1; -} - -void xml_exit(void) -{ - FREE(ns.soap_env); - FREE(ns.soap_enc); - FREE(ns.xsd); - FREE(ns.xsi); - FREE(ns.cwmp); -} - -int xml_send_message(struct cwmp *cwmp, struct session *session, struct rpc *rpc) -{ - char *s, *msg_out = NULL, *msg_in = NULL; - char c[512]; - int msg_out_len = 0, f, r = 0; - mxml_node_t *b; - - if (session->tree_out) { - unsigned char *zmsg_out; - msg_out = mxmlSaveAllocString(session->tree_out, whitespace_cb); - CWMP_LOG_XML_MSG(DEBUG, msg_out, XML_MSG_OUT); - if (cwmp->conf.compression != COMP_NONE) { - if (zlib_compress(msg_out, &zmsg_out, &msg_out_len, cwmp->conf.compression)) { - return -1; - } - FREE(msg_out); - msg_out = (char *)zmsg_out; - } else { - msg_out_len = strlen(msg_out); - } - } - while (1) { - f = 0; - if (http_send_message(cwmp, msg_out, msg_out_len, &msg_in)) { - goto error; - } - if (msg_in) { - CWMP_LOG_XML_MSG(DEBUG, msg_in, XML_MSG_IN); - if ((s = strstr(msg_in, ""))) - sscanf(s, "%d", &f); - if (f) { - if (f == 8005) { - r++; - if (r < 5) { - FREE(msg_in); - continue; - } - goto error; - } else if (rpc && rpc->type != RPC_ACS_INFORM) { - break; - } else { - goto error; - } - } else { - break; - } - } else { - goto end; - } - } - - session->tree_in = mxmlLoadString(NULL, msg_in, MXML_OPAQUE_CALLBACK); - if (!session->tree_in) - goto error; - xml_recreate_namespace(session->tree_in); - /* get NoMoreRequests or HolRequest*/ - session->hold_request = false; - - if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "NoMoreRequests") == -1) - goto error; - b = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); - if (b) { - b = mxmlWalkNext(b, session->tree_in, MXML_DESCEND_FIRST); - if (b && mxmlGetType(b) == MXML_OPAQUE && mxmlGetOpaque(b)) - session->hold_request = atoi(mxmlGetOpaque(b)); - } else { - if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "HoldRequests") == -1) - goto error; - - b = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); - if (b) { - b = mxmlWalkNext(b, session->tree_in, MXML_DESCEND_FIRST); - if (b && mxmlGetType(b) == MXML_OPAQUE && mxmlGetOpaque(b)) - session->hold_request = atoi(mxmlGetOpaque(b)); - } - } - -end: - FREE(msg_out); - FREE(msg_in); - return 0; - -error: - FREE(msg_out); - FREE(msg_in); - return -1; -} - -int xml_prepare_msg_out(struct session *session) -{ - struct cwmp *cwmp = &cwmp_main; - struct config *conf; - conf = &(cwmp->conf); - mxml_node_t *n; - - load_response_xml_schema(&session->tree_out); - if (!session->tree_out) - return -1; - - n = mxmlFindElement(session->tree_out, session->tree_out, "soap_env:Envelope", NULL, NULL, MXML_DESCEND); - if (!n) { - return -1; - } - - mxmlElementSetAttr(n, "xmlns:cwmp", cwmp_urls[(conf->amd_version) - 1]); - if (!session->tree_out) - return -1; - - return 0; -} - -int xml_set_cwmp_id(struct session *session) -{ - char c[32]; - mxml_node_t *b; - - /* define cwmp id */ - if (snprintf(c, sizeof(c), "%u", ++(cwmp_main.cwmp_id)) == -1) - return -1; - - b = mxmlFindElement(session->tree_out, session->tree_out, "cwmp:ID", NULL, NULL, MXML_DESCEND); - if (!b) - return -1; - - b = mxmlNewOpaque(b, c); - if (!b) - return -1; - - return 0; -} - -int xml_set_cwmp_id_rpc_cpe(struct session *session) -{ - char c[512]; - mxml_node_t *b; - - /* handle cwmp:ID */ - if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "ID") == -1) - return -1; - - b = mxmlFindElement(session->tree_in, session->tree_in, c, NULL, NULL, MXML_DESCEND); - - if (b) { - /* ACS send ID parameter */ - b = mxmlWalkNext(b, session->tree_in, MXML_DESCEND_FIRST); - if (!b || mxmlGetType(b) != MXML_OPAQUE || !mxmlGetOpaque(b)) - return 0; - snprintf(c, sizeof(c), "%s", mxmlGetOpaque(b)); - - b = mxmlFindElement(session->tree_out, session->tree_out, "cwmp:ID", NULL, NULL, MXML_DESCEND); - if (!b) - return -1; - - b = mxmlNewOpaque(b, c); - if (!b) - return -1; - } else { - /* ACS does not send ID parameter */ - int r = xml_set_cwmp_id(session); - return r; - } - return 0; -} - -const char *get_node_tab_space(mxml_node_t *node) -{ - static char tab_space[10 * sizeof(CWMP_MXML_TAB_SPACE) + 1]; - int count = 0; - - memset(tab_space, 0, sizeof(tab_space)); - while ((node = mxmlGetParent(node))) { - count = count + 1; - } - - if (count) { - snprintf(tab_space, sizeof(tab_space), "%*s", (int)(count * sizeof(CWMP_MXML_TAB_SPACE)), ""); - } - - return tab_space; -} - -const char *whitespace_cb(mxml_node_t *node, int where __attribute__((unused))) -{ - if (mxmlGetType(node) != MXML_ELEMENT) - return NULL; - - switch (where) { - case MXML_WS_BEFORE_CLOSE: - if (mxmlGetFirstChild(node) && mxmlGetType(mxmlGetFirstChild(node)) != MXML_ELEMENT) - return NULL; - - return get_node_tab_space(node); - case MXML_WS_BEFORE_OPEN: - if (where == MXML_WS_BEFORE_CLOSE && mxmlGetFirstChild(node) && mxmlGetType(mxmlGetFirstChild(node)) != MXML_ELEMENT) - return NULL; - - return get_node_tab_space(node); - case MXML_WS_AFTER_OPEN: - return ((mxmlGetFirstChild(node) == NULL || mxmlGetType(mxmlGetFirstChild(node)) == MXML_ELEMENT) ? "\n" : NULL); - case MXML_WS_AFTER_CLOSE: - return "\n"; - default: - return NULL; - } - - return NULL; -} - -char *xml_get_cwmp_version(int version) -{ - static char versions[60]; - unsigned pos = 0; - int k; - - versions[0] = '\0'; - for (k = 0; k < version; k++) { - pos += snprintf(&versions[pos], sizeof(versions) - pos, "1.%d, ", k); - } - - if (pos) - versions[pos - 2] = 0; - - return versions; -} - -static int xml_prepare_lwnotifications(mxml_node_t *parameter_list) -{ - mxml_node_t *b, *n; - - struct list_head *p; - struct cwmp_dm_parameter *lw_notification; - list_for_each (p, &list_lw_value_change) { - lw_notification = list_entry(p, struct cwmp_dm_parameter, list); - - n = mxmlNewElement(parameter_list, "Param"); - if (!n) - goto error; - - b = mxmlNewElement(n, "Name"); - if (!b) - goto error; - - b = mxmlNewOpaque(b, lw_notification->name); - if (!b) - goto error; - - b = mxmlNewElement(n, "Value"); - if (!b) - goto error; -#ifdef ACS_MULTI - mxmlElementSetAttr(b, "xsi:type", lw_notification->type); -#endif - b = mxmlNewOpaque(b, lw_notification->value); - if (!b) - goto error; - } - return 0; - -error: - return -1; -} - -int xml_prepare_lwnotification_message(char **msg_out) -{ - mxml_node_t *lw_tree; - - load_notification_xml_schema(&lw_tree); - if (!lw_tree) - goto error; - - *msg_out = mxmlSaveAllocString(lw_tree, whitespace_cb); - - mxmlDelete(lw_tree); - return 0; - -error: - return -1; -} - -void load_notification_xml_schema(mxml_node_t **tree) -{ - char declaration[1024] = {0}; - struct cwmp *cwmp = &cwmp_main; - struct config *conf; - conf = &(cwmp->conf); - char *c = NULL; - - if (tree == NULL) - return; - - *tree = NULL; - - snprintf(declaration, sizeof(declaration), "?xml version=\"1.0\" encoding=\"UTF-8\"?"); - mxml_node_t *xml = mxmlNewElement(NULL, declaration); - if (xml == NULL) - return; - - mxml_node_t *notification = mxmlNewElement(xml, "Notification"); - if (notification == NULL) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(notification, "xmlns", "urn:broadband-forum-org:cwmp:lwnotif-1-0"); - mxmlElementSetAttr(notification, "xmlns:xs", xsd_url); - mxmlElementSetAttr(notification, "xmlns:xsi", xsi_url); - mxmlElementSetAttr(notification, "xsi:schemaLocation", "urn:broadband-forum-org:cwmp:lxnotif-1-0 http://www.broadband-forum.org/cwmp/cwmp-UDPLightweightNotification-1-0.xsd"); - - mxml_node_t *ts = mxmlNewElement(notification, "TS"); - if (ts == NULL) { - MXML_DELETE(xml); - return; - } - - if (cwmp_asprintf(&c, "%ld", time(NULL)) == -1) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(ts, c)) { - FREE(c); - MXML_DELETE(xml); - return; - } - - FREE(c); - - mxml_node_t *un = mxmlNewElement(notification, "UN"); - if (un == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(un, conf->acs_userid)) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *cn = mxmlNewElement(notification, "CN"); - if (cn == NULL) { - MXML_DELETE(xml); - return; - } - - c = (char *)calculate_lwnotification_cnonce(); - if (!c) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(cn, c)) { - FREE(c); - MXML_DELETE(xml); - return; - } - - FREE(c); - - mxml_node_t *oui = mxmlNewElement(notification, "OUI"); - if (oui == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(oui, cwmp->deviceid.oui)) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *pclass = mxmlNewElement(notification, "ProductClass"); - if (pclass == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(pclass, cwmp->deviceid.productclass ? cwmp->deviceid.productclass : "")) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *slno = mxmlNewElement(notification, "SerialNumber"); - if (slno == NULL) { - MXML_DELETE(xml); - return; - } - - if (NULL == mxmlNewOpaque(slno, cwmp->deviceid.serialnumber ? cwmp->deviceid.serialnumber : "")) { - MXML_DELETE(xml); - return; - } - - if (xml_prepare_lwnotifications(notification)) { - MXML_DELETE(xml); - return; - } - - *tree = xml; -} - -void load_response_xml_schema(mxml_node_t **schema) -{ - char declaration[1024] = {0}; - - if (schema == NULL) - return; - - *schema = NULL; - - snprintf(declaration, sizeof(declaration), "?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?"); - mxml_node_t *xml = mxmlNewElement(NULL, declaration); - if (xml == NULL) - return; - - mxml_node_t *envlp = mxmlNewElement(xml, "soap_env:Envelope"); - if (envlp == NULL) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(envlp, "xmlns:soap_env", soap_env_url); - mxmlElementSetAttr(envlp, "xmlns:soap_enc", soap_enc_url); - mxmlElementSetAttr(envlp, "xmlns:xsd", xsd_url); - mxmlElementSetAttr(envlp, "xmlns:xsi", xsi_url); - - mxml_node_t *header = mxmlNewElement(envlp, "soap_env:Header"); - if (header == NULL) { - MXML_DELETE(xml); - return; - } - - mxml_node_t *id = mxmlNewElement(header, "cwmp:ID"); - if (id == NULL) { - MXML_DELETE(xml); - return; - } - - mxmlElementSetAttr(id, "soap_env:mustUnderstand", "1"); - - if (NULL == mxmlNewElement(envlp, "soap_env:Body")) { - MXML_DELETE(xml); - return; - } - - *schema = xml; -}