mirror of
https://dev.iopsys.eu/bbf/icwmp.git
synced 2025-12-10 07:44:41 +01:00
1442 lines
44 KiB
C
1442 lines
44 KiB
C
/*
|
|
* xml.c - XML and SOAP functions
|
|
*
|
|
* Copyright (C) 2021-2022, IOPSYS Software Solutions AB.
|
|
*
|
|
* Author Mohamed Kallel <mohamed.kallel@pivasoftware.com>
|
|
* Author Ahmed Zribi <ahmed.zribi@pivasoftware.com>
|
|
* Author Omar Kallel <omar.kallel@pivasoftware.com>
|
|
*
|
|
* 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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
FREE(ns.soap_env);
|
|
FREE(ns.soap_enc);
|
|
FREE(ns.xsd);
|
|
FREE(ns.xsi);
|
|
FREE(ns.cwmp);
|
|
|
|
do {
|
|
char *c;
|
|
|
|
c = (char *)xml__get_attribute_name_by_value(b, soap_env_url);
|
|
if (c && *(c + 5) == ':') {
|
|
FREE(ns.soap_env);
|
|
ns.soap_env = strdup((c + 6));
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
c = (char *)xml__get_attribute_name_by_value(b, soap_enc_url);
|
|
if (c && *(c + 5) == ':') {
|
|
FREE(ns.soap_enc);
|
|
ns.soap_enc = strdup((c + 6));
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
c = (char *)xml__get_attribute_name_by_value(b, xsd_url);
|
|
if (c && *(c + 5) == ':') {
|
|
FREE(ns.xsd);
|
|
ns.xsd = strdup((c + 6));
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
c = (char *)xml__get_attribute_name_by_value(b, xsi_url);
|
|
if (c && *(c + 5) == ':') {
|
|
FREE(ns.xsi);
|
|
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) == ':') {
|
|
FREE(ns.cwmp);
|
|
ns.cwmp = strdup((c + 6));
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (ns.cwmp && ns.soap_env && ns.xsd && ns.soap_enc && ns.xsi)
|
|
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, "<FaultCode>")))
|
|
sscanf(s, "<FaultCode>%d</FaultCode>", &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;
|
|
|
|
if (xml_recreate_namespace(session->tree_in) == -1) {
|
|
CWMP_LOG(ERROR, "Failed to get ns parameters");
|
|
goto error;
|
|
}
|
|
|
|
/* 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;
|
|
}
|