Skip to content
Snippets Groups Projects
libmobile_zte.c 16.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "libmobile_zte.h"
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    struct string {
    	char *ptr;
    	size_t len;
    };
    
    
    static void curl_cleaner(CURLcode *curl);
    
    static size_t write_func(void *buffer, size_t size, size_t nmemb, void *data);
    
    static int apn_profile_idx(struct json_object *apn_profiles, char *name);
    
    static int get_apn_profiles_len(char *ip_addr);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    static char *lexer(const char **input, char *delimiter);
    
    static char *get_query_wrapper(char *ip_addr, char *vars);
    static CURLcode perform_post_request(char *ip_addr, CURL *curl, char *query, struct string *str);
    static CURLcode perform_get_request(char *ip_addr, CURL *curl, char *query, struct string *str);
    
    static struct json_object *perform_request(char *ip_addr, char *query, int option);
    
    static struct json_object *parse_apn_profiles(struct json_object *apn_profiles);
    
    
    /**
     * Function: curl_cleaner
     *
     * Free's the curl environment.
     *
     * Parameters:
     *		curl - The curl easy handle variable.
     */
    
    static void curl_cleaner(CURLcode *curl)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    {
    	curl_easy_cleanup(curl);
    	curl_global_cleanup();
    }
    
    
     * The callback function from performing the curl command, response from server will be reconstructed here.
    
     *
     * Parameters:
     *		buffer - Contains chunk of response from server.
     *		size - Size (byte) of type in buffer array.
     *		nmemb - Number of members in buffer.
    
     *		data - Pointer to area allocated for storing results from server.
    
    Jakob Olsson's avatar
    Jakob Olsson committed
     *		Number of bytes managed (size*nmemb).
    
    static size_t write_func(void *buffer, size_t size, size_t nmemb, void *data)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    {
    
    	struct string *str = (struct string *)data;
    
    	size_t len = size * nmemb;
    
    	size_t new_len = str->len + (len);
    	char *tmp_ptr = str->ptr;
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    	str->ptr = realloc(str->ptr, new_len + 1);
    
    	if (!str->ptr) {
    
    		//debug_print("not enough memory (realloc returned NULL)\n");
    
    		free(tmp_ptr);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		return 0;
    	}
    
    	memcpy(str->ptr + str->len, buffer, len);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	str->ptr[new_len] = '\0';
    	str->len = new_len;
    
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    }
    
    
    /**
     * Function: apn_profile_idx
     *
     * Finds the index of a given profile name from all available profiles.
     *
     * Parameters:
    
     *		apn_profiles - json_object pointer to apn_profiles (gotten from a previous call to <mobile_get_apn_profiles_zte>)
    
     *		name - Name of the APN index for which will be searched.
     *
     * Returns:
     *		Index of the APN on success.
     *		-1 on failure.
     */
    
    static int apn_profile_idx(struct json_object *apn_profiles, char *name)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    	json_object_object_foreach(apn_profiles, key, val) {
    
    		struct json_object *profile_name_json;
    
    		const char *profile_name;
    
    		json_object_object_get_ex(val, "profile_name", &profile_name_json);
    
    		profile_name = json_object_get_string(profile_name_json);
    
    
    		if (strncmp(profile_name, name, 1024) == 0)
    
    /**
     * Function: get_apn_profiles_len
     *
     * Finds the number of APN profiles available.
     *
     * Returns:
     *		Number of APN profiles available on success.
     *		-1 on failure.
     */
    
    static int get_apn_profiles_len(char *ip_addr)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    {
    
    	struct json_object *apn_profiles = mobile_get_apn_profiles_zte(ip_addr);
    
    	if (!apn_profiles) {
    
    		//debug_print("Failed to get apn profiles from server!\n");
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    	json_object_object_foreach(apn_profiles, key, val) {
    		int val_type = json_object_get_type(val);
    
    		if (val_type != json_type_string)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    			len++;
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	}
    
    
    	json_object_put(apn_profiles);
    
    fail:
    	return -1;
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    }
    
    
    /**
     * Function: lexer
     *
     * Take an input string and a delimiter which to split the string on. Returns all characters
     * prior to the delimiter, and removes it from the input string.
     *
     * Parameters:
    
    Jakob Olsson's avatar
    Jakob Olsson committed
     *		input - A character pointer address to the pointer pointing at the string to split.
    
     *		delimiter - A character pointer pointing to the delimiter on which to split the string on.
     *
     * Returns:
     *		A character pointer to the tokens prior to the delimiter on success.
     *		NULL on failure, missing input, delimiter or when no delimiter is present.
     *
     * IMPORTANT NOTE
     *		Will alter the input string and allocate memory for the return value!
    
    Jakob Olsson's avatar
    Jakob Olsson committed
     *		The caller is responsible for freeing the return value.
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    static char *lexer(const char **input, char *delimiter)
    
    	char *token, *substr;
    
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	if (strlen(*input) == 0) {
    
    		//debug_print("empty input!\n");
    
    	} else if (strlen(delimiter) == 0) {
    
    		//debug_print("empty delimiter!\n");
    
    
    	token = strstr(*input, delimiter);
    
    	substr = strdup(*input);
    
    	*input = token + strlen(delimiter);
    
    	return substr;
    }
    
    
    /**
     * Function: get_query_wrapper
    
    Jakob Olsson's avatar
    Jakob Olsson committed
     *		Wraps the input comma-separated values to the appropriate address format for a GET request.
    
     *
     * Parameters:
     *		vars - Char pointer pointing to comma-separated values to retreive.
     *
     * Returns:
     *		The entire query on success.
     *		NULL on failure.
     */
    
    static char *get_query_wrapper(char *ip_addr, char *vars)
    
    	char query[1024] = {0};
    
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	if (strlen(vars) == 0) {
    
    		//debug_print("No GET input provided!\n");
    
    		return NULL;
    	}
    
    	snprintf(query, 1023, "http://%s/goform/goform_get_cmd_process?isTest=false&cmd=%s&multi_data=1", ip_addr, vars);
    
    	//debug_print("query %s\n", query);
    
    	return strdup(query);
    }
    
    
    /**
     * Function: perform_post_request
     *
     * Executes a prepared HTTP POST query through use of the libcurl lbirary.
     *
     * Parameter:
     *		curl - the CURL environment.
    
     *		query - The HTTP POST query to execute.
    
     *		str - a string struct containing the current data pointer and the length of the data currently written.
     *
     * Returns:
     *		The CURLcode indicating the success or failure of the curl execution.
     */
    
    static CURLcode perform_post_request(char *ip_addr, CURL *curl, char *query, struct string *str)
    
    	char post_url[1024] = {0}, referer_url[1024] = {0};
    
    
    	snprintf(referer_url, 1023, "http://%s/index.html", ip_addr);
    	snprintf(post_url, 1023, "http://%s/goform/goform_set_cmd_process", ip_addr);
    
    	curl_easy_setopt(curl, CURLOPT_URL, post_url);
    
    	//curl_easy_setopt(curl, CURLOPT_URL, base_url); //why doesn't this work?
    	curl_easy_setopt(curl, CURLOPT_REFERER, referer_url);
    
    	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, query);
    	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_func);
    	curl_easy_setopt(curl, CURLOPT_WRITEDATA, str);
    
    	return curl_easy_perform(curl);
    }
    
    /**
     * Function: perform_get_request
     *
     * Executes a prepared HTTP GET query through use of the libcurl lbirary.
     *
     * Parameter:
     *		curl - the CURL environment.
    
     *		query - The HTTP GET query to execute.
    
     *		str - a string struct containing the current data pointer and the length of the data currently written.
     *
     * Returns:
     *		The CURLcode indicating the success or failure of the curl execution.
     */
    
    static CURLcode perform_get_request(char *ip_addr, CURL *curl, char *query, struct string *str)
    
    	char referer_url[1024] = {0};
    
    	snprintf(referer_url, 1023, "http://%s/index.html", ip_addr);
    
    	curl_easy_setopt(curl, CURLOPT_URL, query);
    
    	curl_easy_setopt(curl, CURLOPT_REFERER, referer_url);
    
    	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_func);
    	curl_easy_setopt(curl, CURLOPT_WRITEDATA, str);
    
    	return curl_easy_perform(curl);
    }
    
    /**
     * Function: send_post_request
     *
     * Function that prepares curl environment and final POST query, then executes said query.
     *
     * Parameter:
    
     *		query - The POST query content to execute.
    
     *
     * Returns:
     *		A pointer to a json_object containing the JSON response from the server.
     *		NULL on failure.
     */
    
    static struct json_object *perform_request(char *ip_addr, char *query, int option)
    
    	CURL *curl;
    	CURLcode rv;
    	struct string str = {NULL, 0};
    
    	struct json_object *parsed_response;
    
    	str.ptr = (char *)calloc(1, 1);
    
    	if (!str.ptr) {
    
    		//debug_print("Error allocating memory with calloc");
    
    	curl = curl_easy_init();
    	if (!curl) {
    
    		//debug_print("Failed to prepare curl environment!\n");
    
    	if (option == POST)
    
    		rv = perform_post_request(ip_addr, curl, query, &str);
    
    	else if (option == GET) {
    
    		query = get_query_wrapper(ip_addr, query);
    
    		rv = perform_get_request(ip_addr, curl, query, &str);
    
    	} else
    		goto fail_request;
    
    		//debug_print("error performing curl, %s\n", curl_easy_strerror(rv));
    
    	if (!str.ptr)
    		goto fail_ptr;
    
    	//debug_print("%s\n", str.ptr);
    
    	parsed_response = json_tokener_parse(str.ptr);
    
    	if (!parsed_response) {
    
    		//debug_print("No valid JSON, failed parsing!\n");
    
    		goto fail_json;
    	}
    
    	curl_cleaner(curl);
    	free(str.ptr);
    	return parsed_response;
    fail_json:
    fail_ptr:
    
    fail_request:
    
    	curl_cleaner(curl);
    fail_curl:
    	free(str.ptr);
    fail:
    	free(query);
    	return NULL;
    }
    
    /**
     * Function: parse_apn_profiles
     *
     * Takes a string of APN profile configurations provided by zte-mf823 (which is in an awkward, difficult to read format)
     * and transforms them into a more easily read and worked with JSON format.
     *
     * Parameters:
    
     *		apn_profiles - A json_object pointer containing the original apn configuration returned by the dongle.
    
     *		A json_object pointer to apn configurations in a more representative and easier to use format.
    
    static struct json_object *parse_apn_profiles(struct json_object *apn_profiles)
    
    	struct json_object *parsed_profiles = json_object_new_object();
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	int apn_counter = 0;
    
    	char *field_names[13] = {"profile_name", "apn_name", "mode", "wan_dial", "ppp_auth_mode", "ppp_username", "ppp_passwd", "pdp", "pdpd_select", "pdp_addr", "dns_mode", "prefer_dns_manual", "standby_dns_manual"};
    
    	int i;
    	struct json_object *apn_profile;
    	char *field_val;
    	char name[1024] = {0};
    
    	json_object_object_foreach(apn_profiles, key, val) {
    
    		apn_string = json_object_get_string(val);
    		i = 0;
    		apn_profile = json_object_new_object();
    		name[0] = 0;
    
    		if (strlen(apn_string) <= 0) {
    			json_object_put(apn_profile);
    			break;
    		}
    
    
    		while ((field_val = lexer(&apn_string, "($)")) != NULL) {
    			json_object_object_add(apn_profile, field_names[i], json_object_new_string(field_val));
    			i++;
    			free(field_val);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		}
    
    		snprintf(name, 1023, "apn_config_%d", apn_counter);
    
    
    		json_object_object_add(parsed_profiles, name, json_object_get(apn_profile));
    		json_object_put(apn_profile);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		apn_counter++;
    
    	json_object_put(apn_profiles);
    
    struct json_object *mobile_connect_network_zte(char *ip_addr)
    
    	return perform_request(ip_addr, "isTest=false&notCallback=true&goformId=CONNECT_NETWORK", POST);
    
    struct json_object *mobile_disconnect_network_zte(char *ip_addr)
    
    	return perform_request(ip_addr, "isTest=false&notCallback=true&goformId=DISCONNECT_NETWORK", POST);
    
    struct json_object *mobile_delete_apn_profile_zte(char *ip_addr, char *name)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    {
    
    	struct json_object *apn_profiles = mobile_get_apn_profiles_zte(ip_addr);
    
    	char query[1024] = {0};
    	int idx;
    
    	if (!apn_profiles) {
    
    		//debug_print("no response!\n");
    
    	idx = apn_profile_idx(apn_profiles, name);
    
    		//debug_print("APN not found in list!\n");
    
    		goto fail_idx;
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    	snprintf(query, 1023, "isTest=false&apn_action=delete&apn_mode=manual&index=%d&goformId=APN_PROC_EX", idx);
    
    	json_object_put(apn_profiles);
    
    	return perform_request(ip_addr, query, POST);
    
    fail_idx:
    	json_object_put(apn_profiles);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    }
    
    
    struct json_object *mobile_enable_roaming_zte(char *ip_addr)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    {
    
    	return perform_request(ip_addr, "isTest=false&goformId=SET_CONNECTION_MODE&roam_setting_option=on", POST);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    struct json_object *mobile_disable_roaming_zte(char *ip_addr)
    
    	return perform_request(ip_addr, "isTest=false&goformId=SET_CONNECTION_MODE&roam_setting_option=off", POST);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    struct json_object *mobile_get_roam_status_zte(char *ip_addr)
    
    	return perform_request(ip_addr, "roam_setting_option", GET);
    
    struct json_object *mobile_get_current_apn_zte(char *ip_addr)
    
    	struct json_object *current_idx, *idx_json, *apn_profiles, *current_profile;
    	int idx, counter = 0, rv;
    
    	idx_json = perform_request(ip_addr, "Current_index", GET);
    
    		//debug_print("couldn't find index\n");
    
    	json_object_object_get_ex(idx_json, "Current_index", &current_idx);
    	if (!current_idx) {
    		//debug_print("no current idx in response!\n");
    		goto fail_idx;
    	}
    	idx = json_object_get_int(current_idx);
    
    	if (idx < 0 || idx > 9) {
    
    		//debug_print("Something is very wrong!\n");
    
    	apn_profiles = mobile_get_apn_profiles_zte(ip_addr);
    
    
    	json_object_object_foreach(apn_profiles, key, val) {
    		counter++;
    
    		if (counter <= idx)
    
    			continue;
    		current_profile = json_object_get(val);
    		break;
    	}
    
    	json_object_put(idx_json);
    
    	json_object_put(apn_profiles);
    	return current_profile;
    fail_idx:
    	json_object_put(idx_json);
    fail:
    	return NULL;
    }
    
    
    struct json_object *mobile_get_remaining_tries_zte(char *ip_addr)
    
    	return perform_request(ip_addr, "pinnumber", GET);
    
    struct json_object *mobile_get_pin_status_zte(char *ip_addr)
    
    	return perform_request(ip_addr, "pin_status", GET);
    
    struct json_object *mobile_get_rssi_zte(char *ip_addr)
    
    	return perform_request(ip_addr, "lte_rssi", GET);
    
    struct json_object *mobile_get_modem_state_zte(char *ip_addr)
    
    	return perform_request(ip_addr, "&sms_received_flag_flag=0&sts_received_flag_flag=0&cmd=modem_main_state%2Cpin_status%2Cloginfo%2Cnew_version_state%2Ccurrent_upgrade_state%2Cis_mandatory%2Csms_received_flag%2Csts_received_flag%2Csignalbar%2Cnetwork_type%2Cnetwork_provider%2Cppp_status%2CEX_SSID1%2Cex_wifi_status%2CEX_wifi_profile%2Cm_ssid_enable%2Csms_unread_num%2CRadioOff%2Csimcard_roam%2Clan_ipaddr%2Cstation_mac%2Cbattery_charging%2Cbattery_vol_percent%2Cbattery_pers%2Cspn_display_flag%2Cplmn_display_flag%2Cspn_name_data%2Cspn_b1_flag%2Cspn_b2_flag%2Crealtime_tx_bytes%2Crealtime_rx_bytes%2Crealtime_time%2Crealtime_tx_thrpt%2Crealtime_rx_thrpt%2Cmonthly_rx_bytes%2Cmonthly_tx_bytes%2Cmonthly_time%2Cdate_month%2Cdata_volume_limit_switch%2Cdata_volume_limit_size%2Cdata_volume_alert_percent%2Cdata_volume_limit_unit%2Croam_setting_option%2Cupg_roam_switch%2Chplmn", GET);
    
    struct json_object *mobile_get_apn_profiles_zte(char *ip_addr)
    
    	struct json_object *apn_profiles = perform_request(ip_addr, "APN_config0,APN_config1,APN_config2,APN_config3,APN_config4,APN_config5,APN_config6,APN_config7,APN_config8,APN_config9,APN_config10,APN_config11,APN_config12,APN_config13,APN_config14,APN_config15,APN_config16,APN_config17,APN_config18,APN_config19", GET);
    
    	if (!apn_profiles) {
    
    		//debug_print("Error getting profiles!\n");
    
    	return parse_apn_profiles(apn_profiles);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    }
    
    
    struct json_object *mobile_create_apn_profile_zte(char *ip_addr, char *profile_name, char *wan_apn, char *pdp_type)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    {
    
    	snprintf(query, 1023, "isTest=false&goformId=APN_PROC_EX&apn_action=save&apn_mode=manual&profile_name=%s&wan_dial=*99%%23&apn_select=manual&pdp_type=%s&pdp_select=auto&pdp_addr=&index=%d&wan_apn=%s&ppp_auth_mode=none&ppp_username=&ppp_passwd=&dns_mode=auto&prefer_dns_manual=&standby_dns_manual=", profile_name, pdp_type, get_apn_profiles_len(ip_addr), wan_apn);
    
    	return perform_request(ip_addr, query, POST);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    }
    
    
    struct json_object *mobile_set_apn_profile_zte(char *ip_addr, char *name)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    {
    
    	struct json_object *apn_profiles = mobile_get_apn_profiles_zte(ip_addr);
    
    	int idx;
    	char query[1024] = {0};
    
    	if (!apn_profiles) {
    
    		//debug_print("no response!\n");
    
    	idx = apn_profile_idx(apn_profiles, name);
    
    		//debug_print("couldnt find idx, no such profile!\n");
    
    		goto free_idx;
    
    	snprintf(query, 1023, "isTest=false&goformId=APN_PROC_EX&apn_mode=manual&apn_action=set_default&set_default_flag=1&pdp_type=IP&index=%d", idx);
    
    
    	json_object_put(apn_profiles);
    
    	return perform_request(ip_addr, query, POST);
    
    free_idx:
    	json_object_put(apn_profiles);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    }
    
    
    struct json_object *mobile_enable_pin_zte(char *ip_addr, char *pin)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    	snprintf(query, 1023, "isTest=false&goformId=ENABLE_PIN&OldPinNumber=%s&pin_save_flag=0&isTest=false", pin);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    	return perform_request(ip_addr, query, POST);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    }
    
    
    struct json_object *mobile_verify_pin_zte(char *ip_addr, char *pin)
    {
    	return mobile_set_pin_zte(ip_addr, pin, pin);
    }
    
    
    struct json_object *mobile_set_pin_zte(char *ip_addr, char *current_pin, char *new_pin)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    {
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    	snprintf(query, 1023, "isTest=false&goformId=ENABLE_PIN&OldPinNumber=%s&NewPinNumber=%s&pin_save_flag=0&isTest=false", current_pin, new_pin);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    	return perform_request(ip_addr, query, POST);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    }
    
    
    struct json_object *mobile_disable_pin_zte(char *ip_addr, char *pin)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    {
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    	snprintf(query, 1023, "isTest=false&goformId=DISABLE_PIN&OldPinNumber=%s&pin_save_flag=0&isTest=false", pin);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    
    	return perform_request(ip_addr, query, POST);
    
    struct json_object *mobile_unlock_sim_zte(char *ip_addr, char *pin, char *puk)
    
    {
    	char query[1024] = {0};
    
    	snprintf(query, 1023, "isTest=false&goformId=ENTER_PUK&PUKNumber=%s&PinNumber=%s&pin_save_flag=0", puk, pin);
    
    
    	return perform_request(ip_addr, query, POST);