| #include <stdio.h> | |
| #include <pthread.h> | |
| #include "soap.h" | |
| #include "rpc.h" | |
| #include "tr069.h" | |
| #include "tr098.h" | |
| #include "tr069_download.h" | |
| #include "tr069_service.h" | |
| #include "tr069_uci.h" | |
| #include "tr069_msgq.h" | |
| #include "tr069_sys.h" | |
| //#define __return_address() __builtin_return_address(1) | |
| #define __return_address() 0 | |
| int post_factory_reset(void); | |
| int send_tr069_command_delay(struct tr069_task_command * command, unsigned int delay); | |
| int wifi_device_add_trigger(void); | |
| int wifi_ssid_change_trigger(void); | |
| int ipv4_address_change_trigger(void); | |
| int post_add_object(const char * path, const char * name); | |
| int post_system_reset(void); | |
| int tr069_build_oui(void); | |
| void stun_init(void); | |
| extern struct uloop_fd tr069_client_fd; | |
| extern struct tr069_obj root_obj[]; | |
| static char * response_data = NULL; | |
| static int response_len = 0; | |
| #define PRINT_BUF_SIZE 65 | |
| static char print_buf[PRINT_BUF_SIZE]; | |
| unsigned int imcomplete_id = 0; | |
| static void print_string(const char * string) | |
| { | |
| int len = strlen(string); | |
| int printed = 0; | |
| while (printed != len) { | |
| if ((len - printed) > (PRINT_BUF_SIZE - 1)) { | |
| memcpy(print_buf, string + printed, (PRINT_BUF_SIZE - 1)); | |
| printed += (PRINT_BUF_SIZE - 1); | |
| print_buf[PRINT_BUF_SIZE - 1] = '\0'; | |
| } else { | |
| sprintf(print_buf, "%s", string + printed); | |
| printed = len; | |
| } | |
| TR069_DEBUG("[value]%s", print_buf); | |
| } | |
| } | |
| static struct tr069_msg * private_msg = NULL; // This only used in tr069 task | |
| static void tr069_response_cb(char * data, int len, int num, void *cbdata) | |
| { | |
| UNUSED(num); | |
| UNUSED(cbdata); | |
| char * temp; | |
| TR069_DEBUG("[tr069]Get response length %d", len); | |
| temp = tr069_malloc(response_len + len + 1); // Always end by '\0' | |
| if (!temp) { | |
| TR069_ERR("[tr069]Malloc for response store failed..."); | |
| return; | |
| } | |
| memset(temp, 0, response_len + len + 1); | |
| if (response_data) { | |
| TR069_DEBUG("[tr069]Have old string..."); | |
| print_string(response_data); | |
| memcpy(temp, response_data, response_len); | |
| tr069_free(response_data); | |
| response_data = NULL; | |
| } | |
| memcpy(&temp[response_len], data, len); | |
| response_data = temp; | |
| response_len += len; | |
| print_string(temp); | |
| TR069_DEBUG("[tr069]Totoal content length %d", response_len); | |
| } | |
| static void modify_prefix_if_need(void) | |
| { | |
| int temp_index = 0, temp_flag = 0; | |
| temp_index = strlen(tr069_string_prefix) - 1; | |
| while (temp_index > 0) { | |
| if (tr069_string_prefix[temp_index] == '.') { | |
| if (temp_flag == 0) { | |
| temp_flag = 1; | |
| } else { | |
| // Try modify string, if need | |
| char * temp_string = &tr069_string_prefix[temp_index + 1]; | |
| TR069_DEBUG("%s: %s", __func__, temp_string); | |
| if ('0' <= tr069_string_prefix[temp_index + 1] && | |
| '9' >= tr069_string_prefix[temp_index + 1]) { | |
| TR069_DEBUG("need modify"); | |
| tr069_string_prefix[temp_index + 1] = '\0'; | |
| } | |
| return; | |
| } | |
| } | |
| temp_index--; | |
| } | |
| } | |
| static int process_main_tr069_event(void) | |
| { | |
| char * temp_buf = NULL; | |
| char * msg = NULL; | |
| soap_rpc_node * xml_result = NULL; | |
| MrvXMLResults err_info; | |
| struct tr069_msg * tr069_msg = NULL; | |
| struct tr069_rpc_method * method = NULL; | |
| struct http_client * client = NULL; | |
| struct http_client_list * header = NULL; | |
| int state = 1, len = 0, http_response_code = 0; | |
| int fault = 0; | |
| int err = 0; | |
| if (cpe.enable == 0) { | |
| TR069_ERR("TR069 be disabled"); | |
| return 0; | |
| } | |
| if (imcomplete_id) { | |
| TR069_ERR("send_download_imcompete_msg imcomplete_id=%d\n",imcomplete_id); | |
| send_download_imcompete_msg(imcomplete_id); | |
| } | |
| temp_buf = tr069_malloc(BUF_SIZE); | |
| if (!temp_buf) { | |
| TR069_ERR("Malloc failed!@%s:%d", __func__, __LINE__); | |
| err = -1; | |
| goto done; | |
| } | |
| memset(temp_buf, 0, BUF_SIZE); | |
| // Init http client code | |
| // Set URL | |
| client = http_client_init(); | |
| // Set response callback | |
| http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB, tr069_response_cb); | |
| http_client_setopt(client, HTTPCLIENT_OPT_METHOD, HTTPCLIENT_REQUEST_POST); | |
| http_client_setopt(client, HTTPCLIENT_OPT_AUTH_TYPE, HTTP_AUTH_TYPE_BASE); | |
| http_client_setopt(client, HTTPCLIENT_OPT_AUTH_USERNAME, cpe.username); | |
| http_client_setopt(client, HTTPCLIENT_OPT_AUTH_PASSWORD, cpe.password); | |
| // if (!private_msg) { | |
| // TR069_DEBUG("Send Inform msg to ACS"); | |
| // private_msg = tr069_build_msg("1234"); | |
| // tr069_inform_acs(private_msg); | |
| // } else { | |
| // TR069_DEBUG("Send private msg to ACS"); | |
| // } | |
| // tr069_msg = private_msg; | |
| len = 0; | |
| tr069_msg = tr069_build_msg("1234"); | |
| tr069_inform_acs(tr069_msg); | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| TR069_DEBUG("Send to ACS message length: %d", len); | |
| print_string(msg); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| http_client_setopt(client, HTTPCLIENT_OPT_URL, cpe.conn_url); | |
| // Response process main function | |
| do { | |
| // Send SOAP data or empty http ACK, according user setting | |
| TR069_DEBUG("Get SOAP message length %d", len); | |
| if (len > 0) { | |
| // Set private http header, like http type | |
| header = http_client_list_append(header, "Content-Type: text/xml;charset=UTF-8\r\n"); | |
| header = http_client_list_append(header, "SOAPAction:\r\n"); | |
| http_client_setopt(client, HTTPCLIENT_OPT_HTTPHEADER, header); | |
| // Set post data and length | |
| http_client_setopt(client, HTTPCLIENT_OPT_POSTDATA, msg); | |
| http_client_setopt(client, HTTPCLIENT_OPT_POSTLENGTH, len); | |
| } else { | |
| http_client_setopt(client, HTTPCLIENT_OPT_HTTPHEADER, NULL); | |
| http_client_setopt(client, HTTPCLIENT_OPT_POSTDATA, NULL); | |
| http_client_setopt(client, HTTPCLIENT_OPT_POSTLENGTH, 0); | |
| } | |
| // Call http client perform function | |
| http_client_perform(client); | |
| if (msg) { | |
| tr069_free(msg); | |
| msg = NULL; | |
| } | |
| if (header) { | |
| // Free private HTTP header | |
| http_client_list_destroy(header); | |
| header = NULL; | |
| } | |
| http_client_getinfo(client, HTTPCLIENT_GETINFO_RESPONSE_CODE, &http_response_code); | |
| if (http_response_code != 200 && http_response_code != 204) { | |
| TR069_DEBUG("ACS response is not 'HTTP OK'(%d), break process", http_response_code); | |
| err = -1; | |
| state = 0; | |
| break; | |
| } | |
| // Here will be done post data and receive response | |
| if (response_data == NULL) { | |
| TR069_DEBUG("HTTP client recv null string, break process."); | |
| state = 0; | |
| break; | |
| } | |
| // Cover response to xml tree | |
| xml_result = MrvParseXML(response_data, &err_info); | |
| if (!xml_result) { | |
| TR069_DEBUG("Convert response to xml tree failed!"); | |
| break; | |
| } | |
| tr069_free(response_data); | |
| response_data = NULL; | |
| response_len = 0; | |
| // Walk and parse XML tree | |
| walk_and_parse_soap(root, xml_result, &method); | |
| // Free XML tree | |
| TR069_DEBUG("Try free xml tree"); | |
| MrvDeleteRoot(xml_result); | |
| if (method == NULL) { | |
| // If can not get rpc method, break process | |
| TR069_DEBUG("Response to rpc method failed, break process."); | |
| state = 0; | |
| break; | |
| } | |
| // Process ACS response according type | |
| TR069_DEBUG("Get RPC method %d", method->type); | |
| fault = 0; | |
| switch (method->type) { | |
| case RPC_TYPE_FAULT: | |
| TR069_ERR("Handle FAULT!!!"); | |
| state = 0; | |
| break; | |
| case RPC_TYPE_TRANSFER_COMPLETE_RESPONSE: | |
| case RPC_TYPE_INFORM_RESPONSE: { | |
| // If has inform response, means register succssfully | |
| err = 1; | |
| // continue process and send empty http response | |
| if (private_msg) { | |
| msg = MrvCreateXMLString(private_msg->root, 1, &len); | |
| tr069_msg_destroy(private_msg); | |
| private_msg = NULL; | |
| } else { | |
| len = 0; | |
| } | |
| break; | |
| } | |
| case RPC_TYPE_GET_RPC_METHOD: { | |
| // continue process | |
| TR069_DEBUG("Get RPC method list"); | |
| tr069_msg = tr069_build_msg(method->id); | |
| build_get_rpc_method_response(method, tr069_msg); | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| break; | |
| } | |
| case RPC_TYPE_GET_PARAMETER_NAME: { | |
| char * path = method->body.get_param_name.parameter_path; | |
| TR069_DEBUG("Get parameter name"); | |
| tr069_msg = tr069_build_msg(method->id); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:GetParameterNamesResponse", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "ParameterList", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ATTR, "SOAP-ENC:arrayType", "cwmp:ParameterInfoStruct[!^^!]"); | |
| if (path) { | |
| if (is_partial_path(path)) { | |
| struct tr069_obj * p_obj = find_obj(root_obj, path); | |
| if (p_obj) { | |
| tr069_string_prefix = tr069_strdup(path); | |
| modify_prefix_if_need(); | |
| walk_obj_and_paramet(p_obj, top_instance(), parameter_name_dup, tr069_msg, 0); | |
| tr069_free(tr069_string_prefix); | |
| tr069_string_prefix = NULL; | |
| } else { | |
| TR069_ERR("failed @%d: %s", __LINE__, path); | |
| fault = 9003; | |
| } | |
| } else { | |
| struct tr069_param * p_parmet = find_param(root_obj, path); | |
| if (p_parmet) { | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "ParameterInfoStruct", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Name", path); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Writable", p_parmet->rw == TR069_R ? "0" : "1"); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| pop_soap_node(&tr069_msg->body_stack); /* End of ParameterInfoStruct */ | |
| } else { | |
| TR069_ERR("failed @%d: %s", __LINE__, path); | |
| fault = 9003; | |
| } | |
| } | |
| } else { | |
| walk_obj_and_paramet(root_obj, NULL, parameter_name_dup, tr069_msg, 0); | |
| } | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| if (method->body.get_param_name.parameter_path) | |
| tr069_free(method->body.get_param_name.parameter_path); | |
| if (method->body.get_param_name.next_level) | |
| tr069_free(method->body.get_param_name.next_level); | |
| if (fault) { | |
| len = 0; | |
| goto failed; | |
| } | |
| break; | |
| } | |
| case RPC_TYPE_GET_PARAMETER_VALUE: { | |
| struct method_get_param_value * p, *temp_p; | |
| TR069_DEBUG("Get parameter value"); | |
| tr069_msg = tr069_build_msg(method->id); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:GetParameterValuesResponse", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "ParameterList", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ATTR, "SOAP-ENC:arrayType", "cwmp:ParameterValueStruct[!^^!]"); | |
| p = method->body.get_param_value; | |
| if (p == NULL) { | |
| // Need response all parameter value | |
| walk_obj_and_paramet(root_obj, NULL, parameter_value_dup, tr069_msg, 0); | |
| } | |
| while (p) { | |
| temp_p = p->next; | |
| TR069_DEBUG(" parameter path %s", p->string); | |
| if (is_partial_path(p->string)) { | |
| struct tr069_obj * p_obj = find_obj(root_obj, p->string); | |
| if (p_obj == NULL) { | |
| TR069_ERR("Find object failed!"); | |
| tr069_free(p->string); | |
| tr069_free(p); | |
| p = temp_p; | |
| fault = 9003; | |
| continue; | |
| } | |
| tr069_string_prefix = tr069_strdup(p->string); | |
| modify_prefix_if_need(); | |
| walk_obj_and_paramet(p_obj, top_instance(), parameter_value_dup, tr069_msg, 0); | |
| tr069_free(tr069_string_prefix); | |
| tr069_string_prefix = NULL; | |
| } else { | |
| struct tr069_param * p_parameter = find_param(root_obj, p->string); | |
| char * value = NULL; | |
| int get_result; | |
| if ((p_parameter == NULL) || (p_parameter->get_value == NULL)) { | |
| TR069_ERR("Find parameter failed!"); | |
| tr069_free(p->string); | |
| tr069_free(p); | |
| p = temp_p; | |
| fault = 9003; | |
| continue; | |
| } | |
| get_result = p_parameter->get_value(top_instance(), &value); | |
| if (get_result) { | |
| TR069_ERR("Get value failed: %s", p->string); | |
| fault = get_result; | |
| } | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "ParameterValueStruct", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Name", p->string); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Value", value); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ATTR, "xsi:type", rpc_type2string(p_parameter->type)); | |
| if (value) tr069_free(value); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| pop_soap_node(&tr069_msg->body_stack); /* End of ParameterInfoStruct */ | |
| } | |
| tr069_free(p->string); | |
| tr069_free(p); | |
| p = temp_p; | |
| } | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| if (fault) { | |
| len = 0; | |
| goto failed; | |
| } | |
| break; | |
| } | |
| case RPC_TYPE_SET_PARAMETER_VALUE: { | |
| struct method_set_param_value * p = &method->body.set_param_value; | |
| struct method_set_param_value_value * p_value = p->value, * temp; | |
| int set_parameters_invalid = 0; | |
| TR069_DEBUG("Set parameter value with Parameter key: %s", p->parameter_key); | |
| temp = p_value; | |
| // First check all parameters is valid | |
| while (temp) { | |
| struct tr069_param * p_parameter = find_param(root_obj, temp->name); | |
| if (!p_parameter) { | |
| set_parameters_invalid = 1; | |
| TR069_ERR("Not found avalid parameters!"); | |
| fault = 9008; | |
| break; | |
| } | |
| if (!p_parameter->set_value) { | |
| set_parameters_invalid = 1; | |
| TR069_ERR("The parameter not provide set function: %s", temp->name); | |
| fault = 9008; | |
| break; | |
| } | |
| TR069_DEBUG(" set value type is: %s:%s", rpc_type2string(temp->type), rpc_type2string(p_parameter->type)); | |
| if (temp->type != p_parameter->type) { | |
| TR069_ERR("bad type!"); | |
| set_parameters_invalid = 1; | |
| fault = 9008; | |
| break; | |
| } | |
| temp = temp->next; | |
| } | |
| // Next, set parameters value and free struct. If all parameters is valid. | |
| while (p_value) { | |
| int set_result = 0; | |
| struct tr069_param * p_parameter = find_param(root_obj, p_value->name); | |
| temp = p_value->next; | |
| if (set_parameters_invalid) { | |
| TR069_DEBUG(" just free"); | |
| if (p_value->name) tr069_free(p_value->name); | |
| if (p_value->value) tr069_free(p_value->value); | |
| tr069_free(p_value); | |
| p_value = temp; | |
| continue; | |
| } | |
| #if 0 | |
| if (!p_parameter) { | |
| TR069_DEBUG("Get parameter failed or no set function(%s)!", p_value->name); | |
| if (p_value->name) tr069_free(p_value->name); | |
| if (p_value->value) tr069_free(p_value->value); | |
| tr069_free(p_value); | |
| p_value = temp; | |
| fault = 9003; | |
| continue; | |
| } | |
| if (!p_parameter->set_value) { | |
| TR069_DEBUG("Get parameter failed or no set function(%s)!", p_value->name); | |
| if (p_value->name) tr069_free(p_value->name); | |
| if (p_value->value) tr069_free(p_value->value); | |
| tr069_free(p_value); | |
| p_value = temp; | |
| fault = 9008; | |
| continue; | |
| } | |
| #endif | |
| set_result = p_parameter->set_value(top_instance(), p_value->value); | |
| if (set_result) fault = set_result; | |
| if (p_value->name) tr069_free(p_value->name); | |
| if (p_value->value) tr069_free(p_value->value); | |
| tr069_free(p_value); | |
| p_value = temp; | |
| } | |
| if (p->parameter_key) tr069_free(p->parameter_key); | |
| tr069_msg = tr069_build_msg(method->id); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:SetParameterValuesResponse", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Status", "0"); | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| if (fault) { | |
| len = 0; | |
| goto failed; | |
| } | |
| break; | |
| } | |
| case RPC_TYPE_GET_PARAMETER_ATTR: { | |
| struct method_get_attribute_value * p, *temp_p; | |
| TR069_DEBUG("Get parameter attribute"); | |
| tr069_msg = tr069_build_msg(method->id); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:GetParameterAttributesResponse", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "ParameterList", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ATTR, "SOAP-ENC:arrayType", "cwmp:ParameterAttributeStruct[!^^!]"); | |
| p = method->body.get_param_attr; | |
| if (p == NULL) { | |
| // Need response all parameter value | |
| walk_obj_and_paramet(root_obj, NULL, parameter_attr_dup, tr069_msg, 0); | |
| } | |
| while (p) { | |
| temp_p = p->next; | |
| TR069_DEBUG(" parameter path %s", p->string); | |
| if (is_partial_path(p->string)) { | |
| struct tr069_obj * p_obj = find_obj(root_obj, p->string); | |
| if (p_obj == NULL) { | |
| TR069_ERR("Find object failed!"); | |
| tr069_free(p->string); | |
| tr069_free(p); | |
| p = temp_p; | |
| fault = 9003; | |
| continue; | |
| } | |
| tr069_string_prefix = tr069_strdup(p->string); | |
| modify_prefix_if_need(); | |
| walk_obj_and_paramet(p_obj, NULL, parameter_attr_dup, tr069_msg, 0); | |
| tr069_free(tr069_string_prefix); | |
| tr069_string_prefix = NULL; | |
| } else { | |
| struct tr069_param * p_parameter = find_param(root_obj, p->string); | |
| char buf[5]; | |
| if (p_parameter == NULL) { | |
| TR069_ERR("Find parameter failed!"); | |
| tr069_free(p->string); | |
| tr069_free(p); | |
| p = temp_p; | |
| fault = 9003; | |
| continue; | |
| } | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "ParameterAttributeStruct", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Name", p->string); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| sprintf(buf, "%d", p_parameter->notification); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Notification", buf); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "AccessList", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ATTR, "SOAP-ENC:arrayType", rpc_type2string(p_parameter->type)); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "string", "Subscriber"); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| pop_soap_node(&tr069_msg->body_stack); /* End of ParameterAttributeStruct */ | |
| } | |
| tr069_free(p->string); | |
| tr069_free(p); | |
| p = temp_p; | |
| } | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| if (fault) { | |
| len = 0; | |
| goto failed; | |
| } | |
| break; | |
| } | |
| case RPC_TYPE_SET_PARAMETER_ATTR: { | |
| struct method_set_attribute_value * p, *temp_p; | |
| TR069_DEBUG("Set parameter attribute"); | |
| tr069_msg = tr069_build_msg(method->id); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:SetParameterAttributesResponse", NULL); | |
| p = method->body.set_param_attr; | |
| if (p == NULL) { | |
| fault = 9003; | |
| } | |
| while (p) { | |
| temp_p = p->next; | |
| TR069_DEBUG(" parameter path %s", p->name); | |
| if (is_partial_path(p->name)) { | |
| fault = 9003; | |
| } else { | |
| struct tr069_param * p_parameter = find_param(root_obj, p->name); | |
| //char buf[5]; | |
| if (p_parameter == NULL) { | |
| TR069_ERR("Find parameter failed!"); | |
| fault = 9003; | |
| } else { | |
| // Set new attribute to parameters | |
| if (p->notification_change) { | |
| p_parameter->notification = p->notification; | |
| } | |
| } | |
| } | |
| tr069_free(p->name); | |
| tr069_free(p); | |
| p = temp_p; | |
| } | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| if (fault) { | |
| len = 0; | |
| goto failed; | |
| } | |
| break; | |
| } | |
| case RPC_TYPE_REBOOT: { | |
| // Handle reboot command | |
| // Need call reboot system API | |
| struct method_reboot * reboot_des = &method->body.reboot; | |
| tr069_msg = tr069_build_msg(method->id); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:RebootResponse", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Event", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ATTR, "SOAP-ENC:arrayType", "cwmp:EventStruct[!^^!]"); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "EventStruct", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "EventCode", "M Reboot"); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "CommandKey", reboot_des->command_key); | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| tr069_set_uci_info(TR069_PSM_MODULE, "acs_mreboot", "1"); | |
| post_system_reboot(); | |
| break; | |
| } | |
| case RPC_TYPE_FACTORY_RESET: { | |
| // Handle factory reset command | |
| // Need call factory reset system API | |
| tr069_msg = tr069_build_msg(method->id); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:FactoryResetResponse", NULL); | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| post_factory_reset(); | |
| break; | |
| } | |
| case RPC_TYPE_DELETE: | |
| case RPC_TYPE_ADD: { | |
| struct method_add_delete_obj * add_delete; | |
| struct tr069_instance * is = NULL; | |
| struct tr069_obj * obj; | |
| int obj_ret = 0; | |
| add_delete = &method->body.add_delete; | |
| TR069_DEBUG("Add/Delete object with parameter key %s and name %s\n", | |
| add_delete->parameter_key, add_delete->object_name); | |
| obj = find_obj(root_obj, add_delete->object_name); | |
| if (obj) { | |
| // Need add check if object support instance mode | |
| if (method->type == RPC_TYPE_ADD) { | |
| is = malloc_instance(obj, top_instance(), -1); | |
| } else { | |
| is = top_instance(); | |
| // Add delete code | |
| } | |
| if (is) { | |
| // Call user object add function | |
| if (obj->add_obj && method->type == RPC_TYPE_ADD) | |
| obj_ret = obj->add_obj(obj, is); | |
| else if (obj->del_obj && method->type == RPC_TYPE_DELETE) | |
| obj_ret = obj->del_obj(obj, is); | |
| } else { | |
| fault = 9003; | |
| } | |
| } else { | |
| fault = 9003; | |
| } | |
| if (obj_ret && is) { | |
| TR069_ERR("Add/Delete object failed..."); | |
| free_instance(obj, is); | |
| is = NULL; | |
| fault = obj_ret; | |
| } | |
| tr069_msg = tr069_build_msg(method->id); | |
| if (method->type == RPC_TYPE_ADD) { | |
| char buf[16]; | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:AddObjectResponse", NULL); | |
| sprintf(buf, "%d", is ? is->id : -1); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "InstanceNumber", buf); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Status", "0"); | |
| } else { | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:DeleteObjectResponse", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Status", "0"); | |
| } | |
| if (add_delete->object_name) tr069_free(add_delete->object_name); | |
| if (add_delete->parameter_key) tr069_free(add_delete->parameter_key); | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| if (fault) { | |
| len = 0; | |
| goto failed; | |
| } | |
| break; | |
| } | |
| case RPC_TYPE_DOWNLOAD: { | |
| if (cpe.upgrades_managed == 0) { | |
| fault = 9003; | |
| free_download_method(method); | |
| goto failed; | |
| } | |
| if (handle_download_request(&method->body.download)) | |
| { | |
| fault = 9003; | |
| free_download_method(method); | |
| goto failed; | |
| } | |
| tr069_msg = tr069_build_msg(method->id); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:DownloadResponse", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "Status", "1"); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "StartTime", UNKNOWN_TIME); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "CompleteTime", UNKNOWN_TIME); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| len = 0; | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| // The download method memory will free at 'download complete response func' | |
| break; | |
| } | |
| default: | |
| fault = 9003; | |
| TR069_DEBUG("Get unknown reponse type(%d)!", method->type); | |
| failed: | |
| if (tr069_msg) tr069_msg_destroy(tr069_msg); | |
| tr069_msg = tr069_build_msg(method->id); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "SOAP-ENV:Fault", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "faultcode", "Client"); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "faultstring", "CWMP fault"); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "detail", NULL); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "cwmp:Fault", NULL); | |
| sprintf(temp_buf, "%d", fault); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "FaultCode", temp_buf); | |
| pop_soap_node(&tr069_msg->body_stack); | |
| push_new_soap_node(&tr069_msg->body_stack, SOAP_NODE_TYPE_ELEMENT, "FaultString", fault2string(fault)); | |
| // Add code for SetParameterValues RPC call | |
| len = 0; | |
| if (msg) { | |
| tr069_free(msg); | |
| msg = NULL; | |
| } | |
| msg = MrvCreateXMLString(tr069_msg->root, 1, &len); | |
| tr069_msg_destroy(tr069_msg); | |
| tr069_msg = NULL; | |
| } | |
| if (method->id) { | |
| snprintf(cpe.parameter_key, 33, "%s", method->id); | |
| tr069_free(method->id); | |
| } | |
| tr069_free(method); | |
| } while (state); | |
| done: | |
| if (client) http_client_shutdown(client); | |
| if (temp_buf) tr069_free(temp_buf); | |
| response_len = 0; | |
| if (response_data) tr069_free(response_data); | |
| response_data = NULL; | |
| return err; | |
| } | |
| #define MAX_TR069_MSGQ_SIZE 16 | |
| int send_tr069_command(struct tr069_task_command * command) | |
| { | |
| TR069_DEBUG("%s,command_id=%d",__FUNCTION__,command->command_id); | |
| TR069_DEBUG("%s,%p",__FUNCTION__,command); | |
| int len=tr069_MsgQSend((void *)&command,MAX_TR069_MSG_SIZE); | |
| assert(len == MAX_TR069_MSG_SIZE); | |
| return 0; | |
| } | |
| /* | |
| static void __send_tr069_command_delay(unsigned int ctx) | |
| { | |
| struct tr069_task_command * command = (struct tr069_task_command *)ctx; | |
| int len=tr069_MsgQSend((void *)&command,MAX_TR069_MSG_SIZE); | |
| assert(len == MAX_TR069_MSG_SIZE); | |
| } | |
| */ | |
| int send_tr069_command_delay(struct tr069_task_command * command, unsigned int delay) | |
| { | |
| TR069_DEBUG("entry %s",__FUNCTION__); | |
| TR069_DEBUG("%s,command_id=%d",__FUNCTION__,command->command_id); | |
| TR069_DEBUG("%s,%p",__FUNCTION__,command); | |
| int ret=tr069_MsgQSend_dealy((void *)command,delay); | |
| TR069_DEBUG("leave %s",__FUNCTION__); | |
| assert(ret == 0); | |
| return 0; | |
| } | |
| int wifi_device_add_trigger(void) | |
| { | |
| struct tr069_task_command * command = NULL; | |
| if (!tr069_feature_enable) return 0; | |
| command = tr069_malloc(sizeof(struct tr069_task_command)); | |
| if (command) { | |
| memset(command, 0, sizeof(struct tr069_task_command)); | |
| command->command_id = TR069_COMMAND_WIFI_DEVICE_ADD; | |
| return send_tr069_command(command); | |
| } | |
| return 0; | |
| } | |
| int wifi_ssid_change_trigger(void) | |
| { | |
| struct tr069_task_command * command = NULL; | |
| if (!tr069_feature_enable) return 0; | |
| TR069_DEBUG("%s", __func__); | |
| command = tr069_malloc(sizeof(struct tr069_task_command)); | |
| if (command) { | |
| memset(command, 0, sizeof(struct tr069_task_command)); | |
| command->command_id = TR069_COMMAND_WIFI_SSID_CHANGE; | |
| return send_tr069_command(command); | |
| } | |
| return 0; | |
| } | |
| int ipv4_address_change_trigger(void) | |
| { | |
| struct tr069_task_command * command = NULL; | |
| if (!tr069_feature_enable) return 0; | |
| TR069_DEBUG("%s", __func__); | |
| command = tr069_malloc(sizeof(struct tr069_task_command)); | |
| if (command) { | |
| memset(command, 0, sizeof(struct tr069_task_command)); | |
| command->command_id = TR069_COMMAND_NEW_IP_ADDRESS; | |
| return send_tr069_command(command); | |
| } | |
| return 0; | |
| } | |
| int post_add_object(const char * path, const char * name) | |
| { | |
| struct tr069_task_command * cmd = NULL; | |
| if (!tr069_feature_enable) return 0; | |
| cmd = tr069_malloc(sizeof(struct tr069_task_command) + 4); | |
| if (cmd) { | |
| memset(cmd, 0, sizeof(struct tr069_task_command)); | |
| cmd->command_id = TR069_COMMAND_ADDOBJ; | |
| if (path) cmd->msg = (int)tr069_strdup(path); | |
| if (name) cmd->payload[0] = (int)tr069_strdup(name); | |
| return send_tr069_command(cmd); | |
| } | |
| return -1; | |
| } | |
| int post_system_reboot(void) | |
| { | |
| TR069_DEBUG("enter %s",__FUNCTION__); | |
| /* Will be called in tr069 task context */ | |
| struct tr069_task_command * cmd = tr069_malloc(sizeof(struct tr069_task_command)); | |
| if (!cmd) { | |
| TR069_ERR("%s: failed", __func__); | |
| return -1; | |
| } | |
| memset(cmd, 0, sizeof(struct tr069_task_command)); | |
| cmd->command_id = TR069_COMMAND_REBOOT; | |
| cmd->msg = (unsigned int)__return_address(); | |
| TR069_DEBUG("leave %s",__FUNCTION__); | |
| return send_tr069_command(cmd); | |
| } | |
| int post_system_reset(void) | |
| { | |
| /* Will be called in tr069 task context */ | |
| struct tr069_task_command * cmd = tr069_malloc(sizeof(struct tr069_task_command)); | |
| if (!cmd) { | |
| TR069_ERR("%s: failed", __func__); | |
| return -1; | |
| } | |
| memset(cmd, 0, sizeof(struct tr069_task_command)); | |
| cmd->command_id = TR069_COMMAND_RESET; | |
| cmd->msg = (unsigned int)__return_address(); | |
| return send_tr069_command(cmd); | |
| } | |
| int post_factory_reset(void) | |
| { | |
| /* Will be called in tr069 task context */ | |
| struct tr069_task_command * cmd = tr069_malloc(sizeof(struct tr069_task_command)); | |
| if (!cmd) { | |
| TR069_ERR("%s: failed", __func__); | |
| return -1; | |
| } | |
| memset(cmd, 0, sizeof(struct tr069_task_command)); | |
| cmd->command_id = TR069_COMMAND_FACTORY_RESET; | |
| cmd->msg = (unsigned int)__return_address(); | |
| return send_tr069_command(cmd); | |
| } | |
| int post_delay_func(tr069_delay_cb cb, void * context) | |
| { | |
| /* Will be called in tr069 task context */ | |
| struct tr069_task_command * msg = tr069_malloc(sizeof(struct tr069_task_command) + 8); | |
| if (!msg) { | |
| TR069_ERR("%s: Failed", __func__); | |
| return -1; | |
| } | |
| memset(msg, 0, sizeof(struct tr069_task_command) + 8); | |
| msg->command_id = TR069_COMMAND_DELAY_FUNC; | |
| msg->msg = (unsigned int)cb; | |
| msg->payload[0] = (unsigned int)context; | |
| send_tr069_command(msg); | |
| return 0; | |
| } | |
| struct tr069_helper_run_context * malloc_helper_context(void) | |
| { | |
| struct tr069_helper_run_context * context = | |
| tr069_malloc(sizeof(struct tr069_helper_run_context)); | |
| if (context) { | |
| memset(context, 0 , sizeof(sizeof(struct tr069_helper_run_context))); | |
| } | |
| return context; | |
| } | |
| void free_helper_context(struct tr069_helper_run_context * context) | |
| { | |
| context->sem = NULL; | |
| tr069_free(context); | |
| } | |
| int post_to_helper(struct tr069_helper_run_context * context) | |
| { | |
| UNUSED(context); | |
| TR069_DEBUG("%s", __func__); | |
| return 0; | |
| } | |
| static int __tr069_factory_reset(struct tr069_helper_run_context * context) { | |
| // Will run in 'Device management context' | |
| TR069_DEBUG("%s", __func__); | |
| context->result = tr069_malloc(64); | |
| if (context->result) { | |
| int ret=0; | |
| memset(context->result, 0, 64); | |
| TR069_DEBUG("enter %s",__FUNCTION__); | |
| ret=tr069_router_factory_reset(); | |
| TR069_DEBUG("%s: result %d", __func__, ret); | |
| } | |
| return 0; | |
| } | |
| static int tr069_system_reset() { | |
| TR069_DEBUG("enter %s",__FUNCTION__); | |
| tr069_set_uci_info(TR069_PSM_MODULE,TR069_PSM_TAG_BOOT_STATE,"0"); | |
| tr069_router_reboot(); | |
| return TR069_OK; | |
| } | |
| static int tr069_factory_reset() { | |
| struct tr069_helper_run_context * context = malloc_helper_context(); | |
| if (context) { | |
| context->block = 1; | |
| context->cb = __tr069_factory_reset; | |
| post_to_helper(context); | |
| if (context->result) { | |
| tr069_free(context->result); | |
| } | |
| free_helper_context(context); | |
| return TR069_OK; | |
| } | |
| return TR069_9003; | |
| } | |
| struct static_instance { | |
| const char * path; | |
| const char * name; | |
| const char * default_value; | |
| }; | |
| static struct static_instance si[] = { | |
| {"Device.WiFi.SSID.", NULL, "true"}, | |
| {"Device.WiFi.AccessPoint.", NULL, "true"}, | |
| {"Device.Ethernet.Interface.", "LTE", NULL}, | |
| {"Device.DNS.Client.Server.", NULL, "true"}, | |
| }; | |
| static int init_static_instance() | |
| { | |
| int total = sizeof(si) / sizeof(struct static_instance); | |
| char * temp = tr069_malloc(256); | |
| int i; | |
| for (i = 0; i < total; i++) { | |
| struct tr069_instance * is; | |
| int id; | |
| const char * path = si[i].path; | |
| const char * name = si[i].name; | |
| id = rpc_add_obj_api(path, -1, &is); | |
| if (name) { | |
| // The TR181 interface object must contain 'Name' | |
| if (temp) { | |
| struct tr069_param * parameter; | |
| snprintf(temp, 256, "%s%d.Name", path, id); | |
| //TR069_DEBUG("Try find parameter: %s", temp); | |
| parameter = find_param(root_obj, temp); | |
| if (parameter && parameter->set_value) { | |
| //TR069_DEBUG(" Set value %s", name); | |
| parameter->set_value(top_instance(), (char *)name); | |
| } | |
| snprintf(temp, 256, "%s%d.Enable", path, id); | |
| parameter = find_param(root_obj, temp); | |
| //TR069_DEBUG("Try find parameter: %s", temp); | |
| if (parameter && parameter->set_value && si[i].default_value) { | |
| //TR069_DEBUG(" Set value %s", "true"); | |
| parameter->set_value(top_instance(), (char *)(si[i].default_value)); | |
| } | |
| } | |
| } | |
| } | |
| #define MAX_MO_PDP_NUMBER 10 | |
| for (i = 0; i < MAX_MO_PDP_NUMBER; i++) { | |
| struct tr069_instance * is; | |
| int id = rpc_add_obj_api("Device.IP.Interface.", -1, &is); | |
| if (id > 0) { | |
| snprintf(temp, 256, "Device.IP.Interface.%d.IPv4Address.", id); | |
| rpc_add_obj_api(temp, -1, &is); | |
| } | |
| if (id > 0) { | |
| snprintf(temp, 256, "Device.IP.Interface.%d.IPv6Address.", id); | |
| rpc_add_obj_api(temp, -1, &is); | |
| } | |
| } | |
| tr069_free(temp); | |
| temp = NULL; | |
| return 0; | |
| } | |
| extern int tr069_update_assoiated_device(void); | |
| static unsigned int handle_tr069_command(struct tr069_task_command * command) | |
| { | |
| TR069_DEBUG("enter %s,ID=%d",__FUNCTION__,command->command_id); | |
| switch (command->command_id) { | |
| case TR069_COMMAND_IP_CHANGE: { | |
| // TODO: Need add code | |
| return 0; | |
| } | |
| case TR069_COMMAND_STUN_CHANGE: { | |
| unsigned int * p = (unsigned int *)command->msg; | |
| cpe.local_address = p[0]; | |
| cpe.udp_port = p[1]; | |
| struct in_addr temp_addr; | |
| temp_addr.s_addr=cpe.local_address; | |
| TR069_DEBUG("Handle new ip %s with port %d from stun", | |
| inet_ntoa(temp_addr), cpe.udp_port); | |
| cpe.nat_detect = 1; | |
| set_tr069_event(TR069_EVENT_M_CHANGE_DU_STATE, ""); | |
| return 1; | |
| } | |
| case TR069_COMMAND_REQUEST_CONNECT: { | |
| TR069_DEBUG("Handle ACS request connect..."); | |
| set_tr069_event(TR069_EVENT_CONNECTION_REQUEST, ""); | |
| return 1; | |
| } | |
| case TR069_COMMAND_DOWNLOAD_TRIGGER: { | |
| TR069_DEBUG("%s: TR069_COMMAND_DOWNLOAD_TRIGGER", __FUNCTION__); | |
| process_download_request((struct method_download *)command->msg, 1); | |
| return 0; | |
| } | |
| case TR069_COMMAND_DOWNLOAD_COMPLETE: { | |
| TR069_DEBUG("%s: TR069_COMMAND_DOWNLOAD_COMPLETE", __FUNCTION__); | |
| char * psm_string=NULL; | |
| psm_string=tr069_get_uci_info(TR069_PSM_MODULE,"tr069","dimcomplete"); | |
| unsigned int command_id = 0; | |
| char temp_buf[64] = {0}; | |
| if (psm_string){ | |
| TR069_DEBUG("%s: get dimcomplete: %s",__FUNCTION__, psm_string); | |
| memset(temp_buf, 0, 64); | |
| sscanf(psm_string, "[%d]", &command_id); | |
| //command_id=atoi(temp_buf); | |
| if (command_id != 0) { | |
| snprintf(temp_buf, 64, "%d", command_id); | |
| } | |
| TR069_DEBUG("%s: temp_buf %s",__FUNCTION__,temp_buf); | |
| private_msg = (struct tr069_msg *)(command->msg); | |
| set_tr069_event(TR069_EVENT_M_DOWNLOAD, temp_buf); | |
| set_tr069_event(TR069_EVENT_TRANSFER_COMPLETE, temp_buf); | |
| tr069_free(psm_string); | |
| } | |
| return 1; | |
| } | |
| case TR069_COMMAND_REBOOT: { | |
| TR069_DEBUG("Handle reboot command sender %x", command->msg); | |
| tr069_router_reboot(); | |
| return 0; | |
| } | |
| case TR069_COMMAND_RESET: { | |
| TR069_DEBUG("Handle reset..."); | |
| tr069_system_reset(); | |
| return 0; | |
| } | |
| case TR069_COMMAND_FACTORY_RESET: { | |
| TR069_DEBUG("Handle factory reset..."); | |
| tr069_factory_reset(); | |
| return 0; | |
| } | |
| case TR069_COMMAND_DELAY_FUNC: { | |
| tr069_delay_cb cb = (tr069_delay_cb)command->msg; | |
| TR069_DEBUG("Handle dleay function %p", cb); | |
| cb((void *)command->payload[0]); | |
| return 0; | |
| } | |
| case TR069_COMMAND_ADDOBJ: { | |
| char * path = (char *)command->msg; | |
| char * name = (char *)command->payload[0]; | |
| struct tr069_instance * is; | |
| int id = 0; | |
| if(path){ | |
| id = rpc_add_obj_api(path, -1, &is); | |
| if (id < 0) { | |
| TR069_ERR("AddObject failed!(%s)", path); | |
| } else { | |
| if (name) { | |
| // The TR181 interface object must contain 'Name' | |
| char * temp = tr069_malloc(256); | |
| if (temp) { | |
| struct tr069_param * parameter; | |
| snprintf(temp, 256, "%s%d.Name", path, id); | |
| TR069_DEBUG("Try find parameter: %s", temp); | |
| parameter = find_param(root_obj, temp); | |
| if (parameter && parameter->set_value) { | |
| TR069_DEBUG(" Set value %s", name); | |
| parameter->set_value(top_instance(), name); | |
| } | |
| snprintf(temp, 256, "%s%d.Enable", path, id); | |
| parameter = find_param(root_obj, temp); | |
| TR069_DEBUG("Try find parameter: %s", temp); | |
| if (parameter && parameter->set_value) { | |
| TR069_DEBUG(" Set value %s", "true"); | |
| parameter->set_value(top_instance(), "true"); | |
| } | |
| tr069_free(temp); | |
| temp = NULL; | |
| } | |
| } | |
| // TODO: Test code | |
| } | |
| } | |
| if (path) tr069_free(path); | |
| if (name) tr069_free(name); | |
| return 0; | |
| } | |
| case TR069_COMMAND_WIFI_DEVICE_ADD: | |
| tr069_update_assoiated_device(); | |
| return 0; | |
| case TR069_COMMAND_WIFI_SSID_CHANGE: { | |
| #define WIFI_SSID_PATH "Device.WiFi.SSID.1.SSID" | |
| struct tr069_parameter_change_list_struct * temp; | |
| temp = tr069_malloc(sizeof(struct tr069_parameter_change_list_struct)); | |
| if (temp) { | |
| struct tr069_param * param; | |
| snprintf(&temp->parameter_name[0], 200, "%s", WIFI_SSID_PATH); | |
| temp->next = tr069_parameter_change_list; | |
| tr069_parameter_change_list = temp; | |
| TR069_DEBUG("Insert to next info parameter list"); | |
| sleep(1); // Wait 1 sec... for WIFI SSID sync to PSM | |
| param = find_param(root_obj, WIFI_SSID_PATH); | |
| if (param && param->notification == TR069_ACTIVE_NOTIFICATION) { | |
| set_tr069_event(TR069_EVENT_VALUE_CHANGE, ""); | |
| return 1; // Create session immediately | |
| } else { | |
| return 0; // If parameter not present or notification off, will free struct in next acs inform | |
| } | |
| } else { | |
| TR069_ERR("malloc for SSID notify failed"); | |
| return 0; | |
| } | |
| } | |
| case TR069_COMMAND_NEW_IP_ADDRESS: { | |
| #define DEVICE_CONNECTION_REQUEST_URL_PATH "Device.ManagementServer.ConnectionRequestURL" | |
| //1TODO: Now, ConnectionRequestURL in inform list, so not need insert to change_list | |
| //1TODO: So, currently only check notification property, if active then set event to ValueChange | |
| //struct tr069_parameter_change_list_struct * temp; | |
| //temp = malloc(sizeof(struct tr069_parameter_change_list_struct)); | |
| if (1) { | |
| struct tr069_param * param; | |
| //snprintf(&temp->parameter_name[0], 200, "%s", DEVICE_CONNECTION_REQUEST_URL_PATH); | |
| //temp->next = tr069_parameter_change_list; | |
| //tr069_parameter_change_list = temp; | |
| //TR069_DEBUG("Insert to next info parameter list"); | |
| param = find_param(root_obj, DEVICE_CONNECTION_REQUEST_URL_PATH); | |
| if (param && param->notification == TR069_ACTIVE_NOTIFICATION) { | |
| set_tr069_event(TR069_EVENT_VALUE_CHANGE, ""); | |
| return 1; // Create session immediately | |
| } else { | |
| return 0; // If parameter not present or notification off, will free struct in next acs inform | |
| } | |
| } else { | |
| TR069_ERR("malloc for connection request URL notify failed"); | |
| return 0; | |
| } | |
| } | |
| default: | |
| TR069_ERR("Unknow command %d", command->command_id); | |
| return 0; | |
| } | |
| } | |
| static char oui[8] = {0}; | |
| int tr069_build_oui(void) | |
| { | |
| int oui_try_cnt = 3; | |
| unsigned char buf[6]; | |
| while (oui_try_cnt) | |
| { | |
| if (GetWiFiInitStat()) | |
| { | |
| if (tr069_get_wifi_mac((char *)buf)) | |
| { | |
| TR069_ERR("Get OUI try cnt(%d)", oui_try_cnt); | |
| } else { | |
| int i = 0; | |
| for (i = 0; i < 3; i++) { | |
| sprintf(&oui[i*2], "%02x", buf[i]); | |
| } | |
| oui[6] = '\0'; | |
| tr069_oui = oui; | |
| TR069_DEBUG("Get OUI result: %s", tr069_oui); | |
| return 0; | |
| } | |
| } | |
| oui_try_cnt--; | |
| sleep(1); | |
| } | |
| if(oui_try_cnt==0){ | |
| if (tr069_get_br_lan_mac((char *)buf)) | |
| { | |
| TR069_ERR("Get OUI failed(%d)", oui_try_cnt); | |
| } else { | |
| int i = 0; | |
| for (i = 0; i < 3; i++) { | |
| sprintf(&oui[i*2], "%02x", buf[i]); | |
| } | |
| oui[6] = '\0'; | |
| tr069_oui = oui; | |
| TR069_DEBUG("Get OUI result: %s", tr069_oui); | |
| return 0; | |
| } | |
| } | |
| return -1; | |
| } | |
| static unsigned int retry_timer[] = { | |
| (20 * 1000 / 5), | |
| (35 * 1000 / 5), | |
| (60 * 1000 / 5), | |
| (90 * 1000 / 5), | |
| (180 * 1000 / 5), | |
| (320 * 1000 / 5), | |
| (640 * 1000 / 5), | |
| (1280 * 1000 / 5), | |
| (5120 * 1000 / 5), | |
| }; | |
| char IMEI_WEB[MAX_SIM_INFO_STR_LEN] = {0}; | |
| static int retry_index = 0; | |
| #define MAX_RETRY_COUNT (sizeof(retry_timer)/sizeof(unsigned int)) | |
| extern void tr069_wps_notify_cb(unsigned char state); | |
| static int tr069_wait_network_ready() | |
| { | |
| ENTER(); | |
| struct tr069_usock_head receive_msg; | |
| int read_len; | |
| #ifdef __TR069_DEBUG__ | |
| UNUSED(receive_msg); | |
| UNUSED(read_len); | |
| return 0; | |
| #else | |
| loop: | |
| read_len = read(tr069_client_fd.fd, &receive_msg, sizeof(struct tr069_usock_head)); | |
| if(receive_msg.get_id!=TR069_GET_NETWORK_STATUS_ID) | |
| { | |
| goto loop; | |
| } | |
| TR069_DEBUG("%s,network ready:len = %d,id=%d",__FUNCTION__,read_len,receive_msg.get_id); | |
| return 0; | |
| #endif | |
| } | |
| static void * tr069_task(void *data) | |
| { | |
| UNUSED(data); | |
| tr069_client_fd.fd = usock(USOCK_UNIX, TR069_INNER_CONN_SOCKET, NULL); | |
| if (tr069_client_fd.fd < 0) { | |
| TR069_ERR("%s,Failed to connect to server\n",__FUNCTION__); | |
| return NULL; | |
| } | |
| /* | |
| struct timeval timeout_usock={5,0}; | |
| int ret = setsockopt(tr069_client_fd.fd, SOL_SOCKET, SO_RCVTIMEO, &timeout_usock, sizeof(struct timeval)); | |
| if (ret < 0) { | |
| TR069_ERR("tr069_client_fd.fd set tcp recv timeout failed(%d)", ret); | |
| } | |
| */ | |
| TR069_INFO("%s,client fd %d", __FUNCTION__,tr069_client_fd.fd); | |
| unsigned int timeout = 0; | |
| struct tr069_task_command * msg = NULL; | |
| unsigned int inform = 0, event = 0, boot_state = 0, mboot = 0; | |
| TR069_DEBUG("Data: %s %s\n", __DATE__, __TIME__); | |
| tr069_set_firewall_uci_info(); | |
| cpe.enable = 1; | |
| cpe.CWMPRetryIntervalMultiplier = 2000; | |
| cpe.CWMPRetryMiniWaitInterval = 5; | |
| struct uci_context *local_ctx = NULL; | |
| struct uci_element *e = NULL; | |
| struct uci_package *p = NULL; | |
| struct uci_section *uci_sec = NULL; | |
| const char *opt_val = NULL; | |
| if(tr069_MsgQconnect()==-1) | |
| { | |
| return NULL; | |
| } | |
| tr069_wait_network_ready(); | |
| local_ctx = (struct uci_context*)uci_tr069_ctx_get(); | |
| if (!local_ctx) | |
| { | |
| assert(0); | |
| } | |
| uci_foreach_element(&local_ctx->root, e) | |
| { | |
| if (strcmp(e->name, TR069_PSM_MODULE) != 0) | |
| continue; | |
| p = uci_to_package(e); //have found | |
| } | |
| if (!p) | |
| { | |
| uci_load(local_ctx, TR069_PSM_MODULE, &p); | |
| } | |
| if(p) | |
| { | |
| uci_foreach_element(&p->sections, e) | |
| { | |
| uci_sec = uci_to_section(e); | |
| if(strcmp(uci_sec->type, "tr069") == 0) | |
| { | |
| /*dimcomplete*/ | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "dimcomplete"); | |
| if(opt_val && strcmp(opt_val, "0")) | |
| { | |
| TR069_INFO("dimcomplete message valid\n"); | |
| if (1 != sscanf(opt_val, "[%d]", &imcomplete_id)) { | |
| TR069_ERR("imcomplete message parse failed!\n"); | |
| imcomplete_id = 0; | |
| } | |
| } | |
| /*boot_state*/ | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, TR069_PSM_TAG_BOOT_STATE); | |
| if(opt_val && (strcmp(opt_val, "1") == 0)) | |
| { | |
| boot_state=1; | |
| } | |
| TR069_DEBUG("dimcomplete:%d boot_state:%d\n",imcomplete_id,boot_state); | |
| /*acs_mreboot*/ | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "acs_mreboot"); | |
| if(opt_val && (strcmp(opt_val, "1") == 0)) | |
| { | |
| mboot = 1; | |
| tr069_set_uci_info(TR069_PSM_MODULE,"acs_mreboot","0"); | |
| } | |
| TR069_DEBUG("got the tr069 acs_mreboot:%s\n",opt_val); | |
| // Start Inform ACS with bootup | |
| if (boot_state) { | |
| set_tr069_event(TR069_EVENT_BOOT, ""); | |
| if (mboot){ | |
| set_tr069_event(TR069_EVENT_M_REBOOT, ""); | |
| } else { | |
| set_tr069_event(TR069_EVENT_BOOTSTRAP, ""); | |
| } | |
| } | |
| /*username*/ | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, TR069_PSM_TAG_CONNECT_REQUEST_NAME); | |
| if(opt_val) | |
| { | |
| snprintf(cpe.conn_req_username, 32, "%s", opt_val); | |
| } | |
| /*password*/ | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, TR069_PSM_TAG_CONNECT_REQUEST_PSW); | |
| if(opt_val) | |
| { | |
| strncpy(cpe.password, opt_val,32); | |
| } | |
| TR069_DEBUG("Get connection username:%s password:%s\n", cpe.conn_req_username,cpe.password); | |
| /*ACS URL*/ | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, TR069_PSM_TAG_ACSURL); | |
| if (opt_val) { | |
| strncpy(cpe.conn_url, opt_val,90); | |
| } else { | |
| strncpy(cpe.conn_url, tr069_acs_url,90); | |
| } | |
| /*acs_username*/ | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, TR069_PSM_TAG_ACSUSERNAME); | |
| if (opt_val) { | |
| strncpy(cpe.username, opt_val,32); | |
| } else { | |
| strncpy(cpe.username, tr069_acs_username,32); | |
| } | |
| /*ACS password*/ | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, TR069_PSM_TAG_ACSUSERPASSWORD); | |
| if (opt_val) { | |
| strncpy(cpe.password, opt_val,32); | |
| } else { | |
| strncpy(cpe.password, tr069_acs_password,32); | |
| } | |
| TR069_DEBUG("Get ACS URL:[%s] username:[%s] password[%s]\n", | |
| cpe.conn_url, | |
| cpe.username, | |
| cpe.password); | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, TR069_PSM_TAG_INFORM_ENABLE); | |
| if (opt_val) { | |
| cpe.periodic_inform_enable = atoi(opt_val); | |
| } else { | |
| cpe.periodic_inform_enable = tr069_periodic_inform_enable; | |
| } | |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, TR069_PSM_TAG_INFORM_INTERVAL); | |
| if (opt_val) { | |
| TR069_DEBUG("Get INFORM INTERVAL from uci %s\n", opt_val); | |
| cpe.periodic_inform_interval = atoi(opt_val); | |
| } else { | |
| cpe.periodic_inform_interval = tr069_periodic_inform_interval; | |
| } | |
| TR069_DEBUG("Get INFORM enable[%d] interval[%d]\n", | |
| cpe.periodic_inform_enable, | |
| cpe.periodic_inform_interval); | |
| break; | |
| } | |
| } | |
| } | |
| free_tr069_uci_ctx(); | |
| strcpy(cpe.parameter_key, "1234"); | |
| cpe.upgrades_managed = 1; | |
| cpe.connect_request_path = tr069_connect_request_path; | |
| strncpy(cpe.stun_server, stun_server_address,64); | |
| cpe.stun_server_port = stun_server_port; | |
| cpe.stun_enable = stun_enable; | |
| cpe.stun_max_period = cpe.stun_min_period = stun_interval; | |
| sleep(4); | |
| if (!tr069_serial_number) { | |
| memset(IMEI_WEB,0,MAX_SIM_INFO_STR_LEN); | |
| int res=tr069_get_imei_from_ril(IMEI_WEB); | |
| //sint res = TR069_FAIL; | |
| if(res == TR069_SUCCESS){ | |
| TR069_DEBUG("Use IMEI:%s",IMEI_WEB); | |
| tr069_serial_number = (const char *)IMEI_WEB; | |
| }else | |
| { | |
| TR069_DEBUG("Use default SN"); | |
| tr069_serial_number = "5883900"; | |
| } | |
| } | |
| // Wait network prepare... Maybe need change | |
| init_static_instance(); | |
| sleep(4); | |
| if (tr069_oui == NULL) { | |
| tr069_build_oui(); | |
| tr069_oui = oui; | |
| } | |
| do { | |
| int err = 0; | |
| // Recv signal event and process | |
| if (msg) { | |
| // Handle message, like download complete or other situation | |
| event = handle_tr069_command(msg); | |
| if (event) { | |
| inform = 1; | |
| } | |
| } else { | |
| inform = 1; | |
| if (cpe.bootstarp_flag) set_tr069_event(TR069_EVENT_PERIODIC, ""); | |
| } | |
| if (!cpe.bootstarp_flag) { | |
| if (boot_state) { | |
| set_tr069_event(TR069_EVENT_BOOT, ""); | |
| if (mboot) set_tr069_event(TR069_EVENT_M_REBOOT, ""); | |
| } else { | |
| set_tr069_event(TR069_EVENT_BOOTSTRAP, ""); | |
| } | |
| } | |
| if (inform) { | |
| err = process_main_tr069_event(); | |
| if (err < 0) { | |
| TR069_ERR("[tr069]tr069 main event process failed..."); | |
| } else if (err > 0) { | |
| TR069_DEBUG("[tr069]Handle at least one HTTP OK"); | |
| cpe.bootstarp_flag = 1; | |
| if (!boot_state) { | |
| tr069_set_uci_info(TR069_PSM_MODULE,TR069_PSM_TAG_BOOT_STATE,"1"); | |
| } | |
| } else { | |
| } | |
| } | |
| // Clear msg and wait new... | |
| if (msg) { | |
| if (msg->tsk_cmd_cb) msg->tsk_cmd_cb(msg, err); | |
| tr069_free(msg); | |
| msg = NULL; | |
| } | |
| // If periodic inform enabled, recv signal event and timeout | |
| timeout = cpe.periodic_inform_enable ? | |
| (cpe.periodic_inform_interval * 1000 / 5) : 0; | |
| TR069_DEBUG("Inform is %s, timeout %u", | |
| cpe.periodic_inform_enable ? "enable" : "disable", | |
| cpe.periodic_inform_enable ? cpe.periodic_inform_interval : 0); | |
| inform = 0; | |
| if (private_msg) { | |
| tr069_msg_destroy(private_msg); | |
| private_msg = NULL; | |
| } | |
| if (!cpe.bootstarp_flag) { | |
| timeout = retry_timer[retry_index++]; | |
| if ((unsigned int)retry_index >= MAX_RETRY_COUNT) { | |
| retry_index = MAX_RETRY_COUNT - 1; | |
| } | |
| } | |
| tr069_MsgQRecv((void *)&msg, MAX_TR069_MSG_SIZE, timeout); | |
| } while (1); | |
| } | |
| static pthread_t s_tid_StunTask; | |
| extern void * stun_task(void * data); | |
| void stun_init(void) | |
| { | |
| int ret = 0; | |
| ret = pthread_create(&s_tid_StunTask, NULL, stun_task, NULL); | |
| if(ret < 0){ | |
| TR069_ERR("Failed to create stun_task thread, ret:%d",ret); | |
| return; | |
| } | |
| } | |
| static pthread_t s_tid_tr069Server; | |
| void tr069_init(void) | |
| { | |
| if(tr069_feature_enable) | |
| { | |
| TR069_DEBUG("tr069_init..."); | |
| int ret = 0; | |
| ret = pthread_create(&s_tid_tr069Server, NULL, tr069_task, NULL); | |
| if(ret < 0){ | |
| TR069_ERR("Failed to create tr069_task thread, ret:%d",ret); | |
| return; | |
| } | |
| tr069_MsgQCreate(); | |
| stun_init(); | |
| } | |
| } | |