summaryrefslogtreecommitdiffstats
path: root/data.c
diff options
context:
space:
mode:
Diffstat (limited to 'data.c')
-rw-r--r--data.c605
1 files changed, 605 insertions, 0 deletions
diff --git a/data.c b/data.c
new file mode 100644
index 0000000..a88c204
--- /dev/null
+++ b/data.c
@@ -0,0 +1,605 @@
+/*
+ * This file is part of QMI-RIL.
+ *
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ *
+ * QMI-RIL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QMI-RIL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QMI-RIL. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+#define LOG_TAG "RIL"
+#include <utils/Log.h>
+#include <netutils/ifc.h>
+
+#include <qmi-ril.h>
+
+static int qmi2ril_call_fail_cause(QmiWdsCallEndReason cer)
+{
+ switch (cer) {
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_OPERATOR_DETERMINED_BARRING:
+ return PDP_FAIL_OPERATOR_BARRED;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_INSUFFICIENT_RESOURCES:
+ return PDP_FAIL_INSUFFICIENT_RESOURCES;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_APN_TYPE_CONFLICT:
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_UNKNOWN_APN:
+ return PDP_FAIL_MISSING_UKNOWN_APN;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_UNKNOWN_PDP:
+ return PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE;
+ case QMI_WDS_CALL_END_REASON_GENERIC_AUTHENTICATION_FAILED:
+ return PDP_FAIL_USER_AUTHENTICATION;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_GGSN_REJECT:
+ return PDP_FAIL_ACTIVATION_REJECT_GGSN;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_ACTIVATION_REJECT:
+ return PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_OPTION_NOT_SUPPORTED:
+ return PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_OPTION_UNSUBSCRIBED:
+ return PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED;
+ case QMI_WDS_CALL_END_REASON_GENERIC_NO_SERVICE:
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_NO_SERVICE:
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_OPTION_TEMPORARILY_OUT_OF_ORDER:
+ return PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_NSAPI_ALREADY_USED:
+ return PDP_FAIL_NSAPI_IN_USE;
+ case QMI_WDS_CALL_END_REASON_GENERIC_CLOSE_IN_PROGRESS:
+ case QMI_WDS_CALL_END_REASON_GENERIC_RELEASE_NORMAL:
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_REGULAR_DEACTIVATION:
+ return PDP_FAIL_REGULAR_DEACTIVATION;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_PROTOCOL_ERROR:
+ return PDP_FAIL_PROTOCOL_ERRORS;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_MESSAGE_INCORRECT_SEMANTIC:
+ return PDP_FAIL_VOICE_REGISTRATION_FAIL;
+ case QMI_WDS_CALL_END_REASON_GENERIC_ACCESS_FAILURE:
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_NETWORK_FAILURE:
+ return PDP_FAIL_DATA_REGISTRATION_FAIL;
+ case QMI_WDS_CALL_END_REASON_GENERIC_FADE:
+ return PDP_FAIL_SIGNAL_LOST;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_REATTACH_REQUIRED:
+ return PDP_FAIL_PREF_RADIO_TECH_CHANGED;
+ case QMI_WDS_CALL_END_REASON_GENERIC_CLIENT_END:
+ return PDP_FAIL_RADIO_POWER_OFF;
+ case QMI_WDS_CALL_END_REASON_GSM_WCDMA_NETWORK_END:
+ case QMI_WDS_CALL_END_REASON_GENERIC_INTERNAL_ERROR:
+ case QMI_WDS_CALL_END_REASON_GENERIC_ACCESS_ATTEMPT_IN_PROGRESS:
+ case QMI_WDS_CALL_END_REASON_GENERIC_UNSPECIFIED:
+ default:
+ return PDP_FAIL_ERROR_UNSPECIFIED;
+ }
+}
+
+static void qmi2ril_addr4_string(guint32 buf, char **addr4)
+{
+ struct in_addr in_addr_val;
+ char buf4[INET_ADDRSTRLEN];
+
+ in_addr_val.s_addr = GUINT32_TO_BE(buf);
+ memset(buf4, 0, sizeof(buf4));
+ inet_ntop(AF_INET, &in_addr_val, buf4, sizeof(buf4));
+
+ *addr4 = strdup(buf4);
+}
+
+static int qmi2ril_ipv4_netmask_prefix_length(in_addr_t mask)
+{
+ int prefixLength = 0;
+ uint32_t m = (uint32_t)ntohl(mask);
+ while (m & 0x80000000) {
+ prefixLength++;
+ m = m << 1;
+ }
+
+ return prefixLength;
+}
+
+static void ril_setup_data_call_response(RIL_Token token)
+{
+ RIL_Data_Call_Response_v6 response[3];
+ struct ril_data_connection data_connection;
+ size_t size;
+
+ data_connection = ril_data->data_connection;
+ size = sizeof(RIL_Data_Call_Response_v6);
+ memset(&response, 0, sizeof(response));
+
+ response[0].status = data_connection.status;
+ // TODO: should this be set? It's not in Samsung-RIL
+ /* response[0].suggestedRetryTime = -1; */
+ response[0].cid = data_connection.packet_data_handle;
+ response[0].active = data_connection.active;
+ response[0].type = data_connection.type;
+ response[0].ifname = (char*) data_connection.iface;
+ asprintf(&response[0].addresses, "%s/%d", data_connection.ip_addr,
+ qmi2ril_ipv4_netmask_prefix_length(inet_addr(data_connection.subnet_mask)));
+ RIL_LOGD("addresses for response: '%s'", response[0].addresses);
+ if (data_connection.dns1 != NULL && data_connection.dns2 != NULL)
+ asprintf(&response[0].dnses, "%s %s", data_connection.dns1,
+ data_connection.dns2);
+ response[0].gateways = data_connection.gateway;
+
+ if (response[0].status == PDP_FAIL_NONE)
+ ril_request_unsolicited(RIL_UNSOL_DATA_CALL_LIST_CHANGED, &response, size);
+
+ ril_request_complete(token, RIL_E_SUCCESS, &response, size);
+}
+
+static int ril_setup_data_connection(struct ril_data_connection *data_connection)
+{
+ in_addr_t ip_addr;
+ in_addr_t gateway_addr;
+ in_addr_t subnet_mask_addr;
+ in_addr_t dns1_addr;
+ in_addr_t dns2_addr;
+ int rc;
+
+ if (data_connection == NULL || data_connection->iface == NULL
+ || data_connection->ip_addr == NULL
+ || data_connection->gateway == NULL
+ || data_connection->subnet_mask == NULL)
+ return -1;
+
+ ip_addr = inet_addr(data_connection->ip_addr);
+ gateway_addr = inet_addr(data_connection->gateway);
+ subnet_mask_addr = inet_addr(data_connection->subnet_mask);
+
+ if (data_connection->dns1 != NULL)
+ dns1_addr = inet_addr(data_connection->dns1);
+ else
+ dns1_addr = 0;
+
+ if (data_connection->dns2 != NULL)
+ dns2_addr = inet_addr(data_connection->dns2);
+ else
+ dns2_addr = 0;
+
+ rc = ifc_configure(data_connection->iface, ip_addr,
+ qmi2ril_ipv4_netmask_prefix_length(subnet_mask_addr),
+ gateway_addr, dns1_addr, dns2_addr);
+ if (rc < 0)
+ return -1;
+
+ RIL_LOGD("%s: Enabled data connection", __func__);
+
+ return 0;
+}
+
+static void get_current_settings_ready(QmiClientWds *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ GError *error = NULL;
+ QmiMessageWdsGetCurrentSettingsOutput *output;
+ QmiWdsIpFamily ip_family = QMI_WDS_IP_FAMILY_UNSPECIFIED;
+ char *type = strdup("IP");
+ guint32 addr_buf = 0;
+ char *ip_addr = NULL;
+ char *gateway = NULL;
+ char *subnet_mask = NULL;
+ char *dns1 = NULL;
+ char *dns2 = NULL;
+ int rc;
+
+ output = qmi_client_wds_get_current_settings_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_wds_get_current_settings_output_get_result(
+ output, &error)) {
+ RIL_LOGE("%s: error: couldn't get current settings: %s",
+ __func__, error->message);
+ goto error;
+ }
+
+ RIL_LOGD("Current data settings retrieved");
+
+ if (qmi_message_wds_get_current_settings_output_get_ip_family (output, &ip_family, NULL)) {
+ if (ip_family == QMI_WDS_IP_FAMILY_IPV6) {
+ type = strdup("IPV6");
+ RIL_LOGE("TODO: IPv6 support is missing");
+ goto error;
+ }
+ }
+
+ ril_data->data_connection.type = strdup(type);
+
+ if (qmi_message_wds_get_current_settings_output_get_ipv4_address(
+ output, &addr_buf, NULL)) {
+ qmi2ril_addr4_string(addr_buf, &ip_addr);
+ RIL_LOGD("IPv4 address: %s", ip_addr);
+ ril_data->data_connection.ip_addr = strdup(ip_addr);
+ } else {
+ RIL_LOGE("failed to retrieve IPv4 address");
+ goto error;
+ }
+
+ if (qmi_message_wds_get_current_settings_output_get_ipv4_gateway_subnet_mask(
+ output, &addr_buf, NULL)) {
+ qmi2ril_addr4_string(addr_buf, &subnet_mask);
+ RIL_LOGD("IPv4 subnet mask: %s", subnet_mask);
+ ril_data->data_connection.subnet_mask = strdup(subnet_mask);
+ } else if (ip_addr != NULL) {
+ asprintf(&subnet_mask, "255.255.255.255");
+ ril_data->data_connection.subnet_mask = strdup(subnet_mask);
+ }
+
+ if (qmi_message_wds_get_current_settings_output_get_ipv4_gateway_address(
+ output, &addr_buf, NULL)) {
+ qmi2ril_addr4_string(addr_buf, &gateway);
+ RIL_LOGD("IPv4 gateway address: %s", gateway);
+ ril_data->data_connection.gateway = strdup(gateway);
+ } else if (ip_addr != NULL) {
+ RIL_LOGE("failed to retrieve IPv4 gateway");
+ goto error;
+ }
+
+ if (qmi_message_wds_get_current_settings_output_get_primary_ipv4_dns_address(
+ output, &addr_buf, NULL)) {
+ qmi2ril_addr4_string(addr_buf, &dns1);
+ RIL_LOGD("IPv4 primary DNS: %s", dns1);
+ ril_data->data_connection.dns1 = strdup(dns1);
+ }
+
+ if (qmi_message_wds_get_current_settings_output_get_secondary_ipv4_dns_address(
+ output, &addr_buf, NULL)) {
+ qmi2ril_addr4_string(addr_buf, &dns2);
+ RIL_LOGD("IPv4 secondary DNS: %s", dns2);
+ ril_data->data_connection.dns2 = strdup(dns2);
+ }
+
+ rc = ril_setup_data_connection(&ril_data->data_connection);
+ if (rc < 0) {
+ RIL_LOGE("setting up the data connection failed");
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+ qmi_message_wds_get_current_settings_output_unref(
+ output);
+ return;
+ }
+
+error:
+ ril_setup_data_call_response(token);
+
+ if (output)
+ qmi_message_wds_get_current_settings_output_unref(
+ output);
+ if (error)
+ g_error_free(error);
+}
+
+static void
+timeout_get_packet_service_status_ready(QmiClientWds *client,
+ GAsyncResult *res)
+{
+ GError *error = NULL;
+ QmiMessageWdsGetPacketServiceStatusOutput *output;
+ QmiWdsConnectionStatus status;
+
+ output = qmi_client_wds_get_packet_service_status_finish(
+ client, res, &error);
+ if (!output) {
+ RIL_LOGD("%s: error: operation failed: %s", __func__,
+ error->message);
+ g_error_free(error);
+ return;
+ }
+
+ if (!qmi_message_wds_get_packet_service_status_output_get_result (output, &error)) {
+ RIL_LOGD("%s: error: couldn't get packet service status: %s",
+ __func__, error->message);
+ g_error_free(error);
+ qmi_message_wds_get_packet_service_status_output_unref(output);
+ return;
+ }
+
+ qmi_message_wds_get_packet_service_status_output_get_connection_status(
+ output, &status, NULL);
+
+ RIL_LOGD("timout connection status: '%s'",
+ qmi_wds_connection_status_get_string(status));
+ qmi_message_wds_get_packet_service_status_output_unref(output);
+}
+
+static gboolean packet_status_timeout(void)
+{
+ qmi_client_wds_get_packet_service_status(ctx->WdsClient, NULL,
+ 10, ctx->cancellable,
+ (GAsyncReadyCallback)timeout_get_packet_service_status_ready,
+ NULL);
+
+ return TRUE;
+}
+
+static void get_packet_service_status_ready(QmiClientWds *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ GError *error = NULL;
+ QmiMessageWdsGetPacketServiceStatusOutput *output;
+ QmiWdsConnectionStatus status;
+ QmiMessageWdsGetCurrentSettingsInput *input;
+ int active = 0;
+
+ output = qmi_client_wds_get_packet_service_status_finish(
+ client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_wds_get_packet_service_status_output_get_result(output, &error)) {
+ RIL_LOGE("%s: error: couldn't get packet service status: %s",
+ __func__, error->message);
+ goto error;
+ }
+
+ qmi_message_wds_get_packet_service_status_output_get_connection_status(
+ output, &status, NULL);
+
+ RIL_LOGD("Connection status: '%s'",
+ qmi_wds_connection_status_get_string(status));
+
+ if (status == QMI_WDS_CONNECTION_STATUS_CONNECTED)
+ active = 2;
+
+error:
+ ril_data->data_connection.active = active;
+
+ input = qmi_message_wds_get_current_settings_input_new();
+ qmi_message_wds_get_current_settings_input_set_requested_settings(
+ input,
+ (QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_DNS_ADDRESS
+ | QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_IP_ADDRESS
+ | QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_GATEWAY_INFO
+ | QMI_WDS_GET_CURRENT_SETTINGS_REQUESTED_SETTINGS_IP_FAMILY),
+ NULL);
+
+ qmi_client_wds_get_current_settings(ctx->WdsClient,
+ input,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_current_settings_ready,
+ token);
+ qmi_message_wds_get_current_settings_input_unref(input);
+
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_wds_get_packet_service_status_output_unref(output);
+}
+
+static void start_network_ready(QmiClientWds *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ GError *error = NULL;
+ int status = PDP_FAIL_ERROR_UNSPECIFIED;
+ QmiMessageWdsStartNetworkOutput *output;
+ QmiWdsCallEndReason cer;
+ QmiWdsVerboseCallEndReasonType verbose_cer_type;
+ gint16 verbose_cer_reason;
+
+ output = qmi_client_wds_start_network_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_wds_start_network_output_get_result(
+ output, &error)) {
+ RIL_LOGE("%s: error: couldn't start network: %s", __func__,
+ error->message);
+ if (g_error_matches(error, QMI_PROTOCOL_ERROR,
+ QMI_PROTOCOL_ERROR_CALL_FAILED)) {
+ if (qmi_message_wds_start_network_output_get_call_end_reason(
+ output, &cer, NULL)) {
+ RIL_LOGE("call end reason (%u): %s",
+ cer,
+ qmi_wds_call_end_reason_get_string(cer));
+ status = qmi2ril_call_fail_cause(cer);
+ }
+ if (qmi_message_wds_start_network_output_get_verbose_call_end_reason(
+ output, &verbose_cer_type,
+ &verbose_cer_reason, NULL))
+ RIL_LOGE("verbose call end reason (%u,%d): [%s] %s",
+ verbose_cer_type,
+ verbose_cer_reason,
+ qmi_wds_verbose_call_end_reason_type_get_string(verbose_cer_type),
+ qmi_wds_verbose_call_end_reason_get_string(verbose_cer_type, verbose_cer_reason));
+ }
+
+ goto error;
+ }
+
+ status = PDP_FAIL_NONE;
+
+ qmi_message_wds_start_network_output_get_packet_data_handle(
+ output, &ril_data->data_connection.packet_data_handle,
+ NULL);
+ qmi_message_wds_start_network_output_unref(output);
+
+ RIL_LOGD("Network started, packet data handle: '%u'",
+ (guint)ril_data->data_connection.packet_data_handle);
+
+error:
+ ril_data->data_connection.status = status;
+ ril_data->data_connection.iface = strdup(qmi_device_get_wwan_iface(
+ ctx->device));
+
+ qmi_client_wds_get_packet_service_status(ctx->WdsClient,
+ NULL,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_packet_service_status_ready,
+ token);
+
+ // additionally check periodically the connection status
+ ctx->packet_status_timeout_id = g_timeout_add_seconds(
+ 10, (GSourceFunc)packet_status_timeout, NULL);
+
+ if (error)
+ g_error_free(error);
+}
+
+int ril_request_setup_data_call(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ char *apn = NULL;
+ char *username = NULL;
+ char *password = NULL;
+ char **values = NULL;
+ QmiMessageWdsStartNetworkInput *input;
+ int rc;
+
+ if (data == NULL || size < 6 * sizeof(char *))
+ goto error;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
+ if (rc < 0) {
+ ril_request_complete(token, RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW, NULL, 0);
+ return RIL_REQUEST_COMPLETED;
+ }
+
+ request = ril_request_find_request_status(RIL_REQUEST_SETUP_DATA_CALL,
+ RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ if (ril_data->data_connection.raw_ip_mode == FALSE) {
+ RIL_LOGE("error: device is not in raw IP mode!");
+ goto error;
+ }
+
+ values = (char **) data;
+
+ if (values[2] == NULL) {
+ RIL_LOGE("%s: No APN was provided", __func__);
+ goto error;
+ }
+
+ input = qmi_message_wds_start_network_input_new();
+
+ apn = strdup(values[2]);
+ qmi_message_wds_start_network_input_set_apn(input, apn, NULL);
+
+ if (values[3] != NULL) {
+ username = strdup(values[3]);
+ qmi_message_wds_start_network_input_set_username(
+ input, username, NULL);
+ }
+
+ if (values[4] != NULL) {
+ password = strdup(values[4]);
+ qmi_message_wds_start_network_input_set_password(
+ input, password, NULL);
+ }
+
+ qmi_client_wds_start_network(ctx->WdsClient,
+ input,
+ 45,
+ ctx->cancellable,
+ (GAsyncReadyCallback)start_network_ready,
+ token);
+
+ RIL_LOGD("Setting up data connection to APN: %s with username/password: %s/%s",
+ apn, username, password);
+
+ qmi_message_wds_start_network_input_unref(input);
+ strings_array_free(values, size);
+ values = NULL;
+
+ rc = RIL_REQUEST_HANDLED;
+ goto complete;
+
+error:
+ if (values != NULL)
+ strings_array_free(values, size);
+
+ if (apn != NULL)
+ free(apn);
+
+ if (username != NULL)
+ free(username);
+
+ if (password != NULL)
+ free(password);
+
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ rc = RIL_REQUEST_COMPLETED;
+
+complete:
+ return rc;
+}
+
+static void set_data_format_ready(QmiClientWda *client,
+ GAsyncResult *res)
+{
+ QmiMessageWdaSetDataFormatOutput *output;
+ GError *error = NULL;
+ QmiWdaLinkLayerProtocol link_layer_protocol;
+
+ output = qmi_client_wda_set_data_format_finish(client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s\n", __func__,
+ error->message);
+ g_error_free(error);
+ return;
+ }
+
+ if (!qmi_message_wda_set_data_format_output_get_result(output,
+ &error)) {
+ RIL_LOGE("%s: error: couldn't set data format: %s",
+ __func__, error->message);
+ g_error_free(error);
+ qmi_message_wda_set_data_format_output_unref(output);
+ return;
+ }
+
+ RIL_LOGD("[%s] Successfully set data format",
+ qmi_device_get_path_display(ctx->device));
+
+ if (qmi_message_wda_set_data_format_output_get_link_layer_protocol(
+ output, &link_layer_protocol, NULL))
+ RIL_LOGD("Link layer protocol: '%s'",
+ qmi_wda_link_layer_protocol_get_string(link_layer_protocol));
+
+ ril_data->data_connection.raw_ip_mode = TRUE;
+
+ qmi_message_wda_set_data_format_output_unref(output);
+}
+
+void qmi_set_raw_ip_mode(void)
+{
+ QmiMessageWdaSetDataFormatInput *input;
+
+ input = qmi_message_wda_set_data_format_input_new();
+
+ qmi_message_wda_set_data_format_input_set_link_layer_protocol(
+ input,
+ QMI_WDA_LINK_LAYER_PROTOCOL_RAW_IP,
+ NULL);
+
+ qmi_client_wda_set_data_format(ctx->WdaClient, input, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)set_data_format_ready,
+ NULL);
+
+ qmi_message_wda_set_data_format_input_unref(input);
+}