summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk32
-rw-r--r--call.c40
-rw-r--r--data.c605
-rw-r--r--include/plmn_list.h2603
-rwxr-xr-xinclude/plmn_list.sh88
-rw-r--r--include/sim.h51
-rw-r--r--misc.c289
-rw-r--r--network.c664
-rw-r--r--power.c147
-rw-r--r--qmi-client.c347
-rw-r--r--qmi-ril.c1161
-rw-r--r--qmi-ril.h253
-rw-r--r--sim.c695
-rw-r--r--utils.c144
-rw-r--r--utils.h40
15 files changed, 7159 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
index 65c1703..d61dd6c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -20,6 +20,38 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
+ qmi-ril.c \
+ utils.c \
+ power.c \
+ call.c \
+ sim.c \
+ network.c \
+ misc.c \
+ data.c \
+ qmi-client.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/include \
+ external/glib \
+ external/glib/glib \
+ external/glib/gmodule \
+ external/libqmi/src/libqmi-glib \
+ external/libqmi/src/libqmi-glib/generated
+
+LOCAL_CFLAGS := -DRIL_SHLIB
+
+LOCAL_SHARED_LIBRARIES := libcutils libnetutils libutils liblog libpower libcrypto libqmi-glib libgio-2.0 libglib-2.0 libgobject-2.0 libgmodule-2.0
+
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libqmi-ril
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
boot.c \
sahara.c
diff --git a/call.c b/call.c
new file mode 100644
index 0000000..ef6f6cf
--- /dev/null
+++ b/call.c
@@ -0,0 +1,40 @@
+/*
+ * 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 <qmi-ril.h>
+
+int ril_request_get_current_calls(void *data, size_t size, RIL_Token token)
+{
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0) {
+ ril_request_complete(token, RIL_E_SUCCESS, NULL, 0);
+ return RIL_REQUEST_COMPLETED;
+ }
+
+ RIL_LOGD("%s: TODO: implement me", __func__);
+ ril_request_complete(token, RIL_E_SUCCESS, NULL, 0);
+ return RIL_REQUEST_COMPLETED;
+}
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);
+}
diff --git a/include/plmn_list.h b/include/plmn_list.h
new file mode 100644
index 0000000..121dd8d
--- /dev/null
+++ b/include/plmn_list.h
@@ -0,0 +1,2603 @@
+/*
+ * This list was generated from:
+ * http://en.wikipedia.org/wiki/Mobile_country_code
+ *
+ * Date: 07/08/2014 12:54:48
+ * Copyright: Wikipedia Contributors, Creative Commons
+ * Attribution-ShareAlike License
+ */
+
+#ifndef _PLMN_LIST_H_
+#define _PLMN_LIST_H_
+
+#include <stdlib.h>
+
+struct plmn_list_entry {
+ unsigned int mcc;
+ unsigned int mnc;
+ char *operator_long;
+ char *operator_short;
+};
+
+struct plmn_list_entry plmn_list[] = {
+ { 1, 1, "TEST", "TEST" },
+ { 000, 00, "null", "null" },
+
+ // Abkhazia
+
+ { 289, 67, "Aquafon", "Aquafon" },
+ { 289, 88, "A-Mobile", "A-Mobile" },
+
+ // Afghanistan - AF
+
+ { 412, 1, "AWCC", "AWCC" },
+ { 412, 20, "Roshan", "Roshan" },
+ { 412, 40, "MTN", "MTN" },
+ { 412, 50, "Etisalat", "Etisalat" },
+ { 412, 55, "WASEL", "WASEL" },
+ { 412, 80, "Salaam", "Salaam" },
+ { 412, 88, "Salaam", "Salaam" },
+
+ // Albania - AL
+
+ { 276, 1, "AMC", "AMC" },
+ { 276, 2, "Vodafone", "Vodafone" },
+ { 276, 3, "Eagle Mobile", "Eagle Mobile" },
+ { 276, 4, "Plus Communication", "Plus Communication" },
+
+ // Algeria - DZ
+
+ { 603, 1, "Mobilis", "Mobilis" },
+ { 603, 2, "Djezzy", "Djezzy" },
+ { 603, 3, "Ooredoo", "Ooredoo" },
+
+ // American Samoa (United States of America) - AS
+
+ { 544, 11, "Bluesky", "Bluesky" },
+
+ // Andorra - AD
+
+ { 213, 3, "Mobiland", "Mobiland" },
+
+ // Angola - AO
+
+ { 631, 2, "UNITEL", "UNITEL" },
+ { 631, 4, "MOVICEL", "MOVICEL" },
+
+ // Anguilla (United Kingdom) - AI
+
+ { 365, 10, "Weblinks Limited", "Weblinks Limited" },
+ { 365, 840, "LIME", "LIME" },
+
+ // Antigua and Barbuda - AG
+
+ { 344, 30, "APUA", "APUA" },
+ { 344, 50, "Digicel", "Digicel" },
+ { 344, 920, "LIME", "LIME" },
+ { 344, 930, "AT&T Wireless", "AT&T Wireless" },
+
+ // Argentina - AR
+
+ { 722, 10, "Movistar", "Movistar" },
+ { 722, 20, "Nextel", "Nextel" },
+ { 722, 40, "Globalstar", "Globalstar" },
+ { 722, 70, "Movistar", "Movistar" },
+ { 722, 310, "Claro", "Claro" },
+ { 722, 320, "Claro", "Claro" },
+ { 722, 330, "Claro", "Claro" },
+ { 722, 340, "Personal", "Personal" },
+ { 722, 350, "PORT-HABLE", "PORT-HABLE" },
+
+ // Armenia - AM
+
+ { 283, 1, "Beeline", "Beeline" },
+ { 283, 4, "Karabakh Telecom", "Karabakh Telecom" },
+ { 283, 5, "VivaCell-MTS", "VivaCell-MTS" },
+ { 283, 10, "Orange", "Orange" },
+
+ // Aruba (Kingdom of the Netherlands) - AW
+
+ { 363, 1, "SETAR", "SETAR" },
+ { 363, 2, "Digicel", "Digicel" },
+
+ // Australia - AU
+
+ { 505, 1, "Telstra", "Telstra" },
+ { 505, 2, "Optus", "Optus" },
+ { 505, 3, "Vodafone", "Vodafone" },
+ { 505, 4, "Department of Defence", "Department of Defence" },
+ { 505, 5, "Ozitel", "Ozitel" },
+ { 505, 6, "3", "3" },
+ { 505, 7, "Vodafone", "Vodafone" },
+ { 505, 8, "One.Tel", "One.Tel" },
+ { 505, 9, "Airnet", "Airnet" },
+ { 505, 10, "Norfolk Is.", "Norfolk Is." },
+ { 505, 11, "Telstra", "Telstra" },
+ { 505, 12, "3", "3" },
+ { 505, 13, "Railcorp", "Railcorp" },
+ { 505, 14, "AAPT", "AAPT" },
+ { 505, 15, "3GIS", "3GIS" },
+ { 505, 16, "VicTrack", "VicTrack" },
+ { 505, 17, "Vidid Wireless Pty. Ltd.", "Vidid Wireless Pty. Ltd." },
+ { 505, 18, "Pactel", "Pactel" },
+ { 505, 19, "Lycamobile", "Lycamobile" },
+ { 505, 20, "Ausgrid Corporation", "Ausgrid Corporation" },
+ { 505, 21, "Queensland Rail Limited", "Queensland Rail Limited" },
+ { 505, 22, "iiNet Ltd", "iiNet Ltd" },
+ { 505, 23, "Challenge Networks Pty. Ltd.", "Challenge Networks Pty. Ltd." },
+ { 505, 24, "Advanced Communications Technologies Pty. Ltd.", "Advanced Communications Technologies Pty. Ltd." },
+ { 505, 25, "Pilbara Iron Company Services Pty Ltd", "Pilbara Iron Company Services Pty Ltd" },
+ { 505, 26, "Dialogue Communications Pty. Ltd.", "Dialogue Communications Pty. Ltd." },
+ { 505, 27, "Nexium Telecommunications", "Nexium Telecommunications" },
+ { 505, 28, "RCOM International Pty Ltd", "RCOM International Pty Ltd" },
+ { 505, 38, "Crazy John's", "Crazy John's" },
+ { 505, 62, "NBN", "NBN" },
+ { 505, 68, "NBN", "NBN" },
+ { 505, 71, "Telstra", "Telstra" },
+ { 505, 72, "Telstra", "Telstra" },
+ { 505, 88, "Localstar Holding Pty. Ltd.", "Localstar Holding Pty. Ltd." },
+ { 505, 90, "Optus", "Optus" },
+ { 505, 99, "One.Tel", "One.Tel" },
+
+ // Austria - AT
+
+ { 232, 1, "A1 TA", "A1 TA" },
+ { 232, 2, "A1 Telekom Austria", "A1 Telekom Austria" },
+ { 232, 3, "T-Mobile AT", "T-Mobile AT" },
+ { 232, 4, "T-Mobile AT", "T-Mobile AT" },
+ { 232, 5, "Orange AT", "Orange AT" },
+ { 232, 6, "Orange AT", "Orange AT" },
+ { 232, 7, "tele.ring", "tele.ring" },
+ { 232, 9, "Tele2Mobil", "Tele2Mobil" },
+ { 232, 10, "3AT", "3AT" },
+ { 232, 11, "bob", "bob" },
+ { 232, 12, "yesss!", "yesss!" },
+ { 232, 14, "Hutchison Drei Austria", "Hutchison Drei Austria" },
+ { 232, 15, "Vectone", "Vectone" },
+ { 232, 16, "Hutchison Drei Austria", "Hutchison Drei Austria" },
+
+ // Azerbaijan - AZ
+
+ { 400, 1, "Azercell", "Azercell" },
+ { 400, 2, "Bakcell", "Bakcell" },
+ { 400, 3, "FONEX", "FONEX" },
+ { 400, 4, "Nar Mobile", "Nar Mobile" },
+
+ // Bahamas - BS
+
+ { 364, 39, "BaTelCo", "BaTelCo" },
+
+ // Bahrain - BH
+
+ { 426, 1, "Batelco", "Batelco" },
+ { 426, 2, "zain BH", "zain BH" },
+ { 426, 3, "Civil Aviation Authority", "Civil Aviation Authority" },
+ { 426, 4, "VIVA Bahrain", "VIVA Bahrain" },
+ { 426, 5, "Batelco", "Batelco" },
+
+ // Bangladesh - BD
+
+ { 470, 1, "Grameenphone", "Grameenphone" },
+ { 470, 2, "Robi", "Robi" },
+ { 470, 3, "Banglalink", "Banglalink" },
+ { 470, 4, "TeleTalk", "TeleTalk" },
+ { 470, 5, "Citycell", "Citycell" },
+ { 470, 6, "Beeong3G Warid Telekom", "Beeong3G Warid Telekom" },
+ { 470, 7, "Airtel", "Airtel" },
+
+ // Barbados - BB
+
+ { 342, 600, "LIME", "LIME" },
+ { 342, 750, "Digicel", "Digicel" },
+ { 342, 820, "Sunbeach Communications", "Sunbeach Communications" },
+
+ // Belarus - BY
+
+ { 257, 1, "velcom", "velcom" },
+ { 257, 2, "MTS", "MTS" },
+ { 257, 3, "DIALLOG", "DIALLOG" },
+ { 257, 4, "life:)", "life:)" },
+ { 257, 5, "Beltelecom", "Beltelecom" },
+ { 257, 6, "Belorussian Cloud Technologies", "Belorussian Cloud Technologies" },
+ { 257, 501, "BelCel JV", "BelCel JV" },
+
+ // Belgium - BE
+
+ { 206, 1, "Proximus", "Proximus" },
+ { 206, 2, "N.M.B.S.", "N.M.B.S." },
+ { 206, 5, "Telenet", "Telenet" },
+ { 206, 6, "Lycamobile", "Lycamobile" },
+ { 206, 7, "Vectone Mobile", "Vectone Mobile" },
+ { 206, 9, "Voxbone", "Voxbone" },
+ { 206, 10, "Mobistar", "Mobistar" },
+ { 206, 15, "Elephant Talk Communications Schweiz GmbH", "Elephant Talk Communications Schweiz GmbH" },
+ { 206, 20, "BASE", "BASE" },
+
+ // Belize - BZ
+
+ { 702, 67, "DigiCell", "DigiCell" },
+ { 702, 68, "INTELCO", "INTELCO" },
+ { 702, 99, "Smart", "Smart" },
+
+ // Benin - BJ
+
+ { 616, 1, "Libercom", "Libercom" },
+ { 616, 2, "Moov", "Moov" },
+ { 616, 3, "MTN", "MTN" },
+ { 616, 4, "BBCOM", "BBCOM" },
+ { 616, 4, "BLK", "BLK" },
+ { 616, 5, "Glo", "Glo" },
+
+ // Bermuda - BM
+
+ { 310, 59, "Cellular One", "Cellular One" },
+ { 338, 50, "Digicel Bermuda", "Digicel Bermuda" },
+ { 350, 1, "Digicel Bermuda", "Digicel Bermuda" },
+ { 350, 2, "Mobility", "Mobility" },
+
+ // Bhutan - BT
+
+ { 402, 11, "B-Mobile", "B-Mobile" },
+ { 402, 77, "TashiCell", "TashiCell" },
+
+ // Bolivia - BO
+
+ { 736, 1, "Nuevatel", "Nuevatel" },
+ { 736, 2, "Entel", "Entel" },
+ { 736, 3, "Tigo", "Tigo" },
+
+ // Bosnia and Herzegovina - BA
+
+ { 218, 3, "HT-ERONET", "HT-ERONET" },
+ { 218, 5, "m:tel", "m:tel" },
+ { 218, 90, "BH Mobile", "BH Mobile" },
+
+ // Botswana - BW
+
+ { 652, 1, "Mascom", "Mascom" },
+ { 652, 2, "Orange", "Orange" },
+ { 652, 4, "BTC Mobile", "BTC Mobile" },
+
+ // Brazil - BR
+
+ { 724, 2, "TIM", "TIM" },
+ { 724, 3, "TIM", "TIM" },
+ { 724, 4, "TIM", "TIM" },
+ { 724, 5, "Claro BR", "Claro BR" },
+ { 724, 55, "Sercomtel", "Sercomtel" },
+ { 724, 6, "Vivo", "Vivo" },
+ { 724, 10, "Vivo", "Vivo" },
+ { 724, 11, "Vivo", "Vivo" },
+ { 724, 15, "CTBC Celular", "CTBC Celular" },
+ { 724, 16, "Brasil Telecom GSM", "Brasil Telecom GSM" },
+ { 724, 23, "Vivo", "Vivo" },
+ { 724, 31, "Oi", "Oi" },
+ { 724, 32, "CTBC Celular", "CTBC Celular" },
+ { 724, 33, "CTBC Celular", "CTBC Celular" },
+ { 724, 34, "CTBC Celular", "CTBC Celular" },
+ { 724, 39, "Nextel", "Nextel" },
+
+ // British Virgin Islands (United Kingdom) - VG
+
+ { 348, 170, "LIME", "LIME" },
+ { 348, 370, "BVI Cable TV Ltd", "BVI Cable TV Ltd" },
+ { 348, 570, "CCT Boatphone", "CCT Boatphone" },
+ { 348, 770, "Digicel", "Digicel" },
+
+ // Brunei - BN
+
+ { 528, 1, "Jabatan Telekom Brunei", "Jabatan Telekom Brunei" },
+ { 528, 2, "B-Mobile", "B-Mobile" },
+ { 528, 11, "DSTCom", "DSTCom" },
+
+ // Bulgaria - BG
+
+ { 284, 1, "M-Tel", "M-Tel" },
+ { 284, 3, "Vivacom", "Vivacom" },
+ { 284, 5, "GLOBUL", "GLOBUL" },
+ { 284, 7, "НКЖИ", "НКЖИ" },
+ { 284, 9, "COMPATEL LIMITED", "COMPATEL LIMITED" },
+ { 284, 11, "Bulsatcom", "Bulsatcom" },
+ { 284, 13, "Max Telecom", "Max Telecom" },
+
+ // Burkina Faso - BF
+
+ { 613, 1, "Telmob", "Telmob" },
+ { 613, 2, "Airtel", "Airtel" },
+ { 613, 3, "Telecel Faso", "Telecel Faso" },
+
+ // Burundi - BI
+
+ { 642, 1, "Spacetel", "Spacetel" },
+ { 642, 2, "Tempo", "Tempo" },
+ { 642, 3, "Onatel", "Onatel" },
+ { 642, 7, "Smart Mobile", "Smart Mobile" },
+ { 642, 8, "HiTs Telecom", "HiTs Telecom" },
+ { 642, 82, "Leo", "Leo" },
+
+ // Cambodia - KH
+
+ { 456, 1, "Cellcard", "Cellcard" },
+ { 456, 2, "Smart", "Smart" },
+ { 456, 3, "qb", "qb" },
+ { 456, 4, "qb", "qb" },
+ { 456, 5, "Latelz Company Limited", "Latelz Company Limited" },
+ { 456, 6, "Latelz Company Limited", "Latelz Company Limited" },
+ { 456, 8, "Cellcard", "Cellcard" },
+ { 456, 9, "Beeline", "Beeline" },
+ { 456, 11, "Excell", "Excell" },
+ { 456, 18, "Cellcard", "Cellcard" },
+
+ // Cameroon - CM
+
+ { 624, 1, "MTN Cameroon", "MTN Cameroon" },
+ { 624, 2, "Orange", "Orange" },
+
+ // Canada - CA
+
+ { 302, 220, "Telus", "Telus" },
+ { 302, 221, "Telus", "Telus" },
+ { 302, 222, "Telus", "Telus" },
+ { 302, 250, "ALO", "ALO" },
+ { 302, 270, "EastLink", "EastLink" },
+ { 302, 290, "Airtel Wireless", "Airtel Wireless" },
+ { 302, 320, "Mobilicity", "Mobilicity" },
+ { 302, 340, "Execulink", "Execulink" },
+ { 302, 350, "FIRST", "FIRST" },
+ { 302, 360, "MiKe", "MiKe" },
+ { 302, 361, "Telus", "Telus" },
+ { 302, 370, "Fido", "Fido" },
+ { 302, 380, "DMTS", "DMTS" },
+ { 302, 480, "SSi Connexions", "SSi Connexions" },
+ { 302, 490, "WIND Mobile", "WIND Mobile" },
+ { 302, 500, "Videotron", "Videotron" },
+ { 302, 510, "Videotron", "Videotron" },
+ { 302, 530, "Keewatinook Okimacinac", "Keewatinook Okimacinac" },
+ { 302, 560, "Lynx Mobility", "Lynx Mobility" },
+ { 302, 570, "LightSquared", "LightSquared" },
+ { 302, 590, "Quadro Communication", "Quadro Communication" },
+ { 302, 610, "Bell", "Bell" },
+ { 302, 620, "ICE Wireless", "ICE Wireless" },
+ { 302, 630, "Aliant Mobility", "Aliant Mobility" },
+ { 302, 640, "Bell", "Bell" },
+ { 302, 652, "BC Tel Mobility (Telus)", "BC Tel Mobility (Telus)" },
+ { 302, 653, "Telus", "Telus" },
+ { 302, 655, "MTS", "MTS" },
+ { 302, 656, "TBay", "TBay" },
+ { 302, 657, "Telus", "Telus" },
+ { 302, 660, "MTS", "MTS" },
+ { 302, 670, "CityTel Mobility", "CityTel Mobility" },
+ { 302, 680, "SaskTel", "SaskTel" },
+ { 302, 690, "Bell", "Bell" },
+ { 302, 701, "MB Tel Mobility", "MB Tel Mobility" },
+ { 302, 702, "MT&T Mobility (Aliant)", "MT&T Mobility (Aliant)" },
+ { 302, 703, "New Tel Mobility (Aliant)", "New Tel Mobility (Aliant)" },
+ { 302, 710, "Globalstar", "Globalstar" },
+ { 302, 720, "Rogers Wireless", "Rogers Wireless" },
+ { 302, 730, "TerreStar Solutions", "TerreStar Solutions" },
+ { 302, 740, "Shaw Telecom G.P.", "Shaw Telecom G.P." },
+ { 302, 750, "SaskTel", "SaskTel" },
+ { 302, 760, "Public Mobile Inc.", "Public Mobile Inc." },
+ { 302, 770, "Rural Com", "Rural Com" },
+ { 302, 780, "SaskTel", "SaskTel" },
+ { 302, 860, "Telus", "Telus" },
+ { 302, 880, "Bell / Telus / SaskTel", "Bell / Telus / SaskTel" },
+ { 302, 940, "Wightman Telecom", "Wightman Telecom" },
+
+ // Cape Verde - CV
+
+ { 625, 1, "CVMOVEL", "CVMOVEL" },
+ { 625, 2, "T+", "T+" },
+
+ // Cayman Islands (United Kingdom) - KY
+
+ { 346, 140, "LIME", "LIME" },
+ { 346, 50, "Digicel", "Digicel" },
+
+ // Central African Republic - CF
+
+ { 623, 1, "CTP", "CTP" },
+ { 623, 2, "TC", "TC" },
+ { 623, 3, "Orange", "Orange" },
+ { 623, 4, "Nationlink", "Nationlink" },
+
+ // Chad - TD
+
+ { 622, 1, "Airtel", "Airtel" },
+ { 622, 2, "Tchad Mobile", "Tchad Mobile" },
+ { 622, 2, "Tawali", "Tawali" },
+ { 622, 3, "Tigo", "Tigo" },
+ { 622, 4, "Salam", "Salam" },
+
+ // Chile - CL
+
+ { 730, 1, "entel", "entel" },
+ { 730, 2, "movistar", "movistar" },
+ { 730, 3, "Claro", "Claro" },
+ { 730, 4, "Nextel", "Nextel" },
+ { 730, 5, "Multikom S.A.", "Multikom S.A." },
+ { 730, 6, "Blue Two Chile S.A.", "Blue Two Chile S.A." },
+ { 730, 7, "Virgin Mobile", "Virgin Mobile" },
+ { 730, 8, "VTR Móvil", "VTR Móvil" },
+ { 730, 9, "Nextel", "Nextel" },
+ { 730, 10, "entel", "entel" },
+ { 730, 11, "Celupago S.A.", "Celupago S.A." },
+ { 730, 12, "Telestar Móvil S.A.", "Telestar Móvil S.A." },
+ { 730, 13, "Tribe Mobile Chile SPA", "Tribe Mobile Chile SPA" },
+ { 730, 14, "Netline Telefónica Móvil Ltda", "Netline Telefónica Móvil Ltda" },
+ { 730, 15, "Cibeles Telecom S.A.", "Cibeles Telecom S.A." },
+ { 730, 99, "Will", "Will" },
+
+ // China - CN
+
+ { 460, 1, "China Unicom", "China Unicom" },
+ { 460, 2, "China Mobile", "China Mobile" },
+ { 460, 3, "China Telecom", "China Telecom" },
+ { 460, 4, "Global Star Satellite", "Global Star Satellite" },
+ { 460, 5, "China Telecom", "China Telecom" },
+ { 460, 6, "China Unicom", "China Unicom" },
+ { 460, 7, "China Mobile", "China Mobile" },
+ { 460, 20, "China Tietong", "China Tietong" },
+
+ // Christmas Island (Australia) - CX
+
+
+ // Cocos Islands (Australia) - CC
+
+
+ // Colombia - CO
+
+ { 732, 1, "Colombia Telecomunicaciones S.A.", "Colombia Telecomunicaciones S.A." },
+ { 732, 2, "Edatel", "Edatel" },
+ { 732, 20, "Emtelsa", "Emtelsa" },
+ { 732, 99, "EMCALI", "EMCALI" },
+ { 732, 101, "Claro", "Claro" },
+ { 732, 102, "movistar", "movistar" },
+ { 732, 103, "Tigo", "Tigo" },
+ { 732, 111, "Tigo", "Tigo" },
+ { 732, 123, "movistar", "movistar" },
+ { 732, 130, "AVANTEL", "AVANTEL" },
+ { 732, 123, "Virgin Mobile Colombia", "Virgin Mobile Colombia" },
+
+ // Comoros - KM
+
+ { 654, 1, "Comoros Telecom", "Comoros Telecom" },
+
+ // Republic of the Congo - CG
+
+ { 629, 1, "Airtel", "Airtel" },
+ { 629, 7, "Warid Telecom", "Warid Telecom" },
+ { 629, 10, "Libertis Telecom", "Libertis Telecom" },
+
+ // Cook Islands (New Zealand) - CK
+
+ { 548, 1, "Telecom Cook", "Telecom Cook" },
+
+ // Costa Rica - CR
+
+ { 712, 1, "Kolbi ICE", "Kolbi ICE" },
+ { 712, 2, "Kolbi ICE", "Kolbi ICE" },
+ { 712, 3, "Claro", "Claro" },
+ { 712, 4, "movistar", "movistar" },
+ { 712, 20, "'''full'''móvil", "'''full'''móvil" },
+
+ // Croatia - HR
+
+ { 219, 1, "T-Mobile", "T-Mobile" },
+ { 219, 2, "Tele2", "Tele2" },
+ { 219, 10, "Vip", "Vip" },
+
+ // Cuba - CU
+
+ { 368, 1, "CUBACEL", "CUBACEL" },
+
+ // Cyprus - CY
+
+ { 280, 1, "Cytamobile-Vodafone", "Cytamobile-Vodafone" },
+ { 280, 10, "MTN", "MTN" },
+ { 280, 20, "PrimeTel", "PrimeTel" },
+ { 280, 22, "lemontel", "lemontel" },
+
+ // Czech Republic - CZ
+
+ { 230, 1, "T-Mobile", "T-Mobile" },
+ { 230, 2, "O2", "O2" },
+ { 230, 3, "Vodafone", "Vodafone" },
+ { 230, 4, "U:fon", "U:fon" },
+ { 230, 5, "TRAVEL TELEKOMMUNIKATION, s.r.o.", "TRAVEL TELEKOMMUNIKATION, s.r.o." },
+ { 230, 6, "OSNO TELECOMUNICATION, s.r.o.", "OSNO TELECOMUNICATION, s.r.o." },
+ { 230, 7, "ASTELNET, s.r.o.", "ASTELNET, s.r.o." },
+ { 230, 8, "Compatel s.r.o.", "Compatel s.r.o." },
+ { 230, 98, "Správa železniční dopravní cesty, s.o.", "Správa železniční dopravní cesty, s.o." },
+ { 230, 99, "Vodafone", "Vodafone" },
+
+ // Democratic Republic of the Congo - CD
+
+ { 630, 1, "Vodacom", "Vodacom" },
+ { 630, 2, "airtel", "airtel" },
+ { 630, 4, "Cellco", "Cellco" },
+ { 630, 5, "Supercell", "Supercell" },
+ { 630, 10, "Libertis Telecom", "Libertis Telecom" },
+ { 630, 86, "Orange", "Orange" },
+ { 630, 88, "YTT", "YTT" },
+ { 630, 89, "Tigo", "Tigo" },
+ { 630, 90, "Africell", "Africell" },
+
+ // Denmark (Kingdom of Denmark) - DK
+
+ { 238, 1, "TDC", "TDC" },
+ { 238, 2, "Telenor", "Telenor" },
+ { 238, 3, "End2End", "End2End" },
+ { 238, 4, "NextGen Mobile Ltd", "NextGen Mobile Ltd" },
+ { 238, 5, "TetraNet", "TetraNet" },
+ { 238, 6, "3", "3" },
+ { 238, 7, "Vectone Mobile", "Vectone Mobile" },
+ { 238, 8, "Voxbone", "Voxbone" },
+ { 238, 9, "SINE", "SINE" },
+ { 238, 10, "TDC", "TDC" },
+ { 238, 11, "SINE", "SINE" },
+ { 238, 12, "Lycamobile", "Lycamobile" },
+ { 238, 13, "Compatel Limited", "Compatel Limited" },
+ { 238, 20, "Telia", "Telia" },
+ { 238, 23, "GSM-R DK", "GSM-R DK" },
+ { 238, 28, "CoolTEL ApS", "CoolTEL ApS" },
+ { 238, 30, "Interactive digital media GmbH", "Interactive digital media GmbH" },
+ { 238, 40, "Ericsson Danmark A/S", "Ericsson Danmark A/S" },
+ { 238, 43, "MobiWeb Limited", "MobiWeb Limited" },
+ { 238, 66, "TT-Netværket P/S", "TT-Netværket P/S" },
+ { 238, 77, "Telenor", "Telenor" },
+
+ // Djibouti - DJ
+
+ { 638, 1, "Evatis", "Evatis" },
+
+ // Dominica - DM
+
+ { 366, 20, "Digicel", "Digicel" },
+ { 366, 110, "Cable & Wireless", "Cable & Wireless" },
+
+ // Dominican Republic - DO
+
+ { 370, 1, "Orange", "Orange" },
+ { 370, 2, "Claro", "Claro" },
+ { 370, 3, "Tricom", "Tricom" },
+ { 370, 4, "Viva", "Viva" },
+
+ // East Timor - TL
+
+ { 514, 1, "Telin Telkomcel", "Telin Telkomcel" },
+ { 514, 2, "Timor Telecom", "Timor Telecom" },
+ { 514, 3, "Viettel Timor-Leste", "Viettel Timor-Leste" },
+
+ // Ecuador - EC
+
+ { 740, 1, "Claro", "Claro" },
+ { 740, 2, "CNT Mobile", "CNT Mobile" },
+
+ // Egypt - EG
+
+ { 602, 1, "Mobinil", "Mobinil" },
+ { 602, 2, "Vodafone", "Vodafone" },
+ { 602, 3, "Etisalat", "Etisalat" },
+
+ // El Salvador - SV
+
+ { 706, 1, "CTE Telecom Personal, Claro", "CTE Telecom Personal, Claro" },
+ { 706, 2, "digicel", "digicel" },
+ { 706, 3, "Tigo", "Tigo" },
+ { 706, 4, "movistar", "movistar" },
+
+ // Equatorial Guinea - GQ
+
+ { 627, 1, "Orange GQ", "Orange GQ" },
+ { 627, 3, "Hits GQ", "Hits GQ" },
+
+ // Eritrea - ER
+
+ { 657, 1, "Eritel", "Eritel" },
+
+ // Estonia - EE
+
+ { 248, 1, "EMT", "EMT" },
+ { 248, 2, "Elisa", "Elisa" },
+ { 248, 3, "Tele 2", "Tele 2" },
+ { 248, 4, "OY Top Connect", "OY Top Connect" },
+ { 248, 5, "AS Bravocom Mobiil", "AS Bravocom Mobiil" },
+ { 248, 6, "Progroup Holding", "Progroup Holding" },
+ { 248, 7, "Televõrgu AS", "Televõrgu AS" },
+ { 248, 8, "VIVEX", "VIVEX" },
+ { 248, 9, "Bravo Telecom", "Bravo Telecom" },
+ { 248, 71, "Siseministeerium (Ministry of Interior)", "Siseministeerium (Ministry of Interior)" },
+
+ // Ethiopia - ET
+
+ { 636, 1, "ETH-MTN", "ETH-MTN" },
+
+ // Faroe Islands (Kingdom of Denmark) - FO
+
+ { 288, 1, "Faroese Telecom", "Faroese Telecom" },
+ { 288, 2, "Vodafone", "Vodafone" },
+ { 288, 3, "Edge Mobile Sp/F", "Edge Mobile Sp/F" },
+
+ // Fiji - FJ
+
+ { 542, 1, "Vodafone", "Vodafone" },
+ { 542, 2, "Digicel", "Digicel" },
+ { 542, 3, "Telecom Fiji Ltd", "Telecom Fiji Ltd" },
+
+ // Finland - FI
+
+ { 244, 3, "DNA", "DNA" },
+ { 244, 4, "AINA", "AINA" },
+ { 244, 5, "Elisa", "Elisa" },
+ { 244, 7, "Nokia", "Nokia" },
+ { 244, 8, "Nokia", "Nokia" },
+ { 244, 9, "Finnet Group / Nokia Solutions and Networks", "Finnet Group / Nokia Solutions and Networks" },
+ { 244, 10, "TDC", "TDC" },
+ { 244, 11, "Vectone Mobile", "Vectone Mobile" },
+ { 244, 12, "DNA", "DNA" },
+ { 244, 13, "DNA", "DNA" },
+ { 244, 14, "Ålcom", "Ålcom" },
+ { 244, 15, "SAMK", "SAMK" },
+ { 244, 16, "Oy Finland Tele2 AB", "Oy Finland Tele2 AB" },
+ { 244, 21, "Saunalahti", "Saunalahti" },
+ { 244, 25, "Datame", "Datame" },
+ { 244, 26, "Compatel", "Compatel" },
+ { 244, 29, "SCNL Truphone", "SCNL Truphone" },
+ { 244, 30, "Vectone Mobile", "Vectone Mobile" },
+ { 244, 31, "Ukko Mobile", "Ukko Mobile" },
+ { 244, 32, "Voxbone", "Voxbone" },
+ { 244, 91, "Sonera", "Sonera" },
+
+ // France - FR
+
+ { 208, 1, "Orange", "Orange" },
+ { 208, 2, "Orange", "Orange" },
+ { 208, 3, "MobiquiThings", "MobiquiThings" },
+ { 208, 4, "Sisteer", "Sisteer" },
+ { 208, 5, "Globalstar Europe", "Globalstar Europe" },
+ { 208, 6, "Globalstar Europe", "Globalstar Europe" },
+ { 208, 7, "Globalstar Europe", "Globalstar Europe" },
+ { 208, 8, "Completel Mobile", "Completel Mobile" },
+ { 208, 9, "SFR", "SFR" },
+ { 208, 10, "SFR", "SFR" },
+ { 208, 11, "SFR", "SFR" },
+ { 208, 13, "SFR", "SFR" },
+ { 208, 14, "RFF", "RFF" },
+ { 208, 15, "Free Mobile", "Free Mobile" },
+ { 208, 16, "Free Mobile", "Free Mobile" },
+ { 208, 17, "LEGOS", "LEGOS" },
+ { 208, 18, "Voxbone", "Voxbone" },
+ { 208, 20, "Bouygues", "Bouygues" },
+ { 208, 21, "Bouygues", "Bouygues" },
+ { 208, 22, "Transatel Mobile", "Transatel Mobile" },
+ { 208, 23, "Virgin Mobile (MVNO)", "Virgin Mobile (MVNO)" },
+ { 208, 24, "MobiquiThings", "MobiquiThings" },
+ { 208, 25, "LycaMobile", "LycaMobile" },
+ { 208, 26, "NRJ Mobile (MVNO)", "NRJ Mobile (MVNO)" },
+ { 208, 27, "Afone", "Afone" },
+ { 208, 28, "Astrium SAS", "Astrium SAS" },
+ { 208, 29, "Société International Mobile Communication", "Société International Mobile Communication" },
+ { 208, 30, "Symacom", "Symacom" },
+ { 208, 31, "Vectone", "Vectone" },
+ { 208, 88, "Bouygues", "Bouygues" },
+ { 208, 89, "Omer Telecom Ltd", "Omer Telecom Ltd" },
+ { 208, 90, "Images & Réseaux", "Images & Réseaux" },
+ { 208, 91, "Orange S.A.", "Orange S.A." },
+ { 208, 92, "Com4Innov", "Com4Innov" },
+ { 208, 93, "TDF", "TDF" },
+
+ // French Guiana (France) - GF
+
+
+ // French Polynesia (France) - PF
+
+ { 547, 10, "Mara Telecom", "Mara Telecom" },
+ { 547, 15, "Vodafone", "Vodafone" },
+ { 547, 20, "Vini", "Vini" },
+
+ // French Southern Territories (France) - TF
+
+
+ // Gabon - GA
+
+ { 628, 1, "Libertis", "Libertis" },
+ { 628, 2, "Moov", "Moov" },
+ { 628, 3, "Airtel", "Airtel" },
+ { 628, 4, "Azur", "Azur" },
+ { 628, 5, "RAG", "RAG" },
+
+ // Gambia - GM
+
+ { 607, 1, "Gamcel", "Gamcel" },
+ { 607, 2, "Africel", "Africel" },
+ { 607, 3, "Comium", "Comium" },
+ { 607, 4, "QCell", "QCell" },
+
+ // Georgia - GE
+
+ { 282, 1, "Geocell", "Geocell" },
+ { 282, 2, "MagtiCom", "MagtiCom" },
+ { 282, 3, "MagtiCom", "MagtiCom" },
+ { 282, 4, "Beeline", "Beeline" },
+ { 282, 5, "Silknet", "Silknet" },
+ { 282, 6, "JSC Compatel", "JSC Compatel" },
+ { 282, 7, "GlobalCell Ltd", "GlobalCell Ltd" },
+
+ // Germany - DE
+
+ { 262, 1, "Telekom", "Telekom" },
+ { 262, 2, "Vodafone", "Vodafone" },
+ { 262, 3, "E-Plus", "E-Plus" },
+ { 262, 4, "Vodafone", "Vodafone" },
+ { 262, 5, "E-Plus", "E-Plus" },
+ { 262, 6, "T-Mobile", "T-Mobile" },
+ { 262, 7, "O2", "O2" },
+ { 262, 8, "O2", "O2" },
+ { 262, 9, "Vodafone", "Vodafone" },
+ { 262, 10, "DB Netz AG", "DB Netz AG" },
+ { 262, 11, "O2", "O2" },
+ { 262, 12, "Dolphin Telecom / sipgate", "Dolphin Telecom / sipgate" },
+ { 262, 13, "Mobilcom Multimedia", "Mobilcom Multimedia" },
+ { 262, 14, "Group 3G UMTS", "Group 3G UMTS" },
+ { 262, 15, "Airdata", "Airdata" },
+ { 262, 16, "Telogic ex. Vistream", "Telogic ex. Vistream" },
+ { 262, 17, "E-Plus", "E-Plus" },
+ { 262, 18, "NetCologne", "NetCologne" },
+ { 262, 19, "Inquam Deutschland", "Inquam Deutschland" },
+ { 262, 20, "OnePhone", "OnePhone" },
+ { 262, 41, "First Telecom GmbH", "First Telecom GmbH" },
+ { 262, 42, "CCC Event", "CCC Event" },
+ { 262, 43, "LYCA", "LYCA" },
+ { 262, 60, "DB Telematik", "DB Telematik" },
+ { 262, 76, "Siemens AG", "Siemens AG" },
+ { 262, 77, "E-Plus", "E-Plus" },
+ { 262, 78, "T-Mobile", "T-Mobile" },
+ { 262, 79, "ng4T GmbH", "ng4T GmbH" },
+ { 262, 92, "Nash Technologies", "Nash Technologies" },
+ { 262, 901, "Debitel", "Debitel" },
+
+ // Ghana - GH
+
+ { 620, 1, "MTN", "MTN" },
+ { 620, 2, "Vodafone", "Vodafone" },
+ { 620, 3, "tiGO", "tiGO" },
+ { 620, 4, "Expresso", "Expresso" },
+ { 620, 6, "Airtel", "Airtel" },
+ { 620, 7, "Globacom", "Globacom" },
+ { 620, 11, "Netafrique Dot Com Ltd", "Netafrique Dot Com Ltd" },
+
+ // Gibraltar (United Kingdom) - GI
+
+ { 266, 1, "GibTel", "GibTel" },
+ { 266, 6, "CTS Mobile", "CTS Mobile" },
+ { 266, 9, "Shine", "Shine" },
+
+ // Greece - GR
+
+ { 202, 1, "Cosmote", "Cosmote" },
+ { 202, 2, "Cosmote", "Cosmote" },
+ { 202, 3, "OTE", "OTE" },
+ { 202, 4, "EDISY", "EDISY" },
+ { 202, 5, "Vodafone", "Vodafone" },
+ { 202, 6, "Cosmoline", "Cosmoline" },
+ { 202, 7, "AMD Telecom", "AMD Telecom" },
+ { 202, 9, "Wind", "Wind" },
+ { 202, 10, "Wind", "Wind" },
+
+ // Greenland (Kingdom of Denmark) - GL
+
+ { 290, 1, "TELE Greenland A/S", "TELE Greenland A/S" },
+
+ // Grenada - GD
+
+ { 352, 30, "Digicel", "Digicel" },
+ { 352, 110, "Cable & Wireless", "Cable & Wireless" },
+
+ // Guadeloupe (France) - GP
+
+ { 340, 1, "Orange", "Orange" },
+ { 340, 2, "Outremer", "Outremer" },
+ { 340, 3, "Telcell", "Telcell" },
+ { 340, 8, "Dauphin", "Dauphin" },
+ { 340, 20, "Digicel", "Digicel" },
+
+ // Guam (United States of America) - GU
+
+ { 310, 32, "IT&E Wireless", "IT&E Wireless" },
+ { 310, 33, "Guam Telephone Authority", "Guam Telephone Authority" },
+ { 310, 140, "mPulse", "mPulse" },
+ { 311, 250, "i CAN_GSM", "i CAN_GSM" },
+ { 310, 370, "Docomo", "Docomo" },
+ { 310, 470, "Docomo", "Docomo" },
+
+ // Guatemala - GT
+
+ { 704, 1, "Claro", "Claro" },
+ { 704, 2, "Tigo", "Tigo" },
+ { 704, 3, "movistar", "movistar" },
+
+ // Guernsey (United Kingdom) - GG
+
+ { 234, 3, "Airtel Vodafone", "Airtel Vodafone" },
+ { 234, 50, "Wave Telecom", "Wave Telecom" },
+ { 234, 55, "Sure Mobile", "Sure Mobile" },
+
+ // Guinea - GN
+
+ { 611, 1, "Orange S.A.", "Orange S.A." },
+ { 611, 2, "Sotelgui", "Sotelgui" },
+ { 611, 3, "Telecel Guinee", "Telecel Guinee" },
+ { 611, 4, "MTN", "MTN" },
+ { 611, 5, "Cellcom", "Cellcom" },
+
+ // Guinea-Bissau - GW
+
+ { 632, 1, "Guinetel", "Guinetel" },
+ { 632, 2, "MTN Areeba", "MTN Areeba" },
+ { 632, 3, "Orange", "Orange" },
+ { 632, 7, "Guinetel", "Guinetel" },
+
+ // Guyana - GY
+
+ { 738, 1, "Digicel", "Digicel" },
+ { 738, 2, "GT&T Cellink Plus", "GT&T Cellink Plus" },
+
+ // Haiti - HT
+
+ { 372, 1, "Voila", "Voila" },
+ { 372, 2, "Digicel", "Digicel" },
+ { 372, 3, "Natcom", "Natcom" },
+
+ // Honduras - HN
+
+ { 708, 1, "Claro", "Claro" },
+ { 708, 2, "Tigo", "Tigo" },
+ { 708, 30, "Hondutel", "Hondutel" },
+ { 708, 40, "Digicel", "Digicel" },
+
+ // Hong Kong - HK
+
+ { 454, 1, "CITIC Telecom 1616", "CITIC Telecom 1616" },
+ { 454, 2, "CSL Limited", "CSL Limited" },
+ { 454, 3, "3", "3" },
+ { 454, 4, "3 (2G)", "3 (2G)" },
+ { 454, 5, "3 (CDMA)", "3 (CDMA)" },
+ { 454, 6, "SmarTone", "SmarTone" },
+ { 454, 7, "China Unicom (Hong Kong) Limited", "China Unicom (Hong Kong) Limited" },
+ { 454, 8, "Truphone", "Truphone" },
+ { 454, 9, "China Motion Telecom", "China Motion Telecom" },
+ { 454, 10, "New World Mobility", "New World Mobility" },
+ { 454, 11, "China-Hong Kong Telecom", "China-Hong Kong Telecom" },
+ { 454, 12, "CMCC HK", "CMCC HK" },
+ { 454, 13, "CMCC HK", "CMCC HK" },
+ { 454, 14, "Hutchison Telecom", "Hutchison Telecom" },
+ { 454, 15, "SmarTone Mobile Communications Limited", "SmarTone Mobile Communications Limited" },
+ { 454, 16, "PCCW Mobile (2G)", "PCCW Mobile (2G)" },
+ { 454, 17, "SmarTone Mobile Communications Limited", "SmarTone Mobile Communications Limited" },
+ { 454, 18, "CSL Limited", "CSL Limited" },
+ { 454, 19, "PCCW Mobile (3G/4G)", "PCCW Mobile (3G/4G)" },
+ { 454, 22, "P Plus", "P Plus" },
+ { 454, 29, "PCCW Mobile (CDMA)", "PCCW Mobile (CDMA)" },
+
+ // Hungary - HU
+
+ { 216, 1, "Telenor", "Telenor" },
+ { 216, 20, "Telenor", "Telenor" },
+ { 216, 30, "T-Mobile", "T-Mobile" },
+ { 216, 70, "Vodafone", "Vodafone" },
+ { 216, 71, "UPC Hungary", "UPC Hungary" },
+ { 216, 99, "MAV GSM-R", "MAV GSM-R" },
+
+ // Iceland - IS
+
+ { 274, 1, "Síminn", "Síminn" },
+ { 274, 2, "Vodafone", "Vodafone" },
+ { 274, 3, "Vodafone", "Vodafone" },
+ { 274, 4, "Viking", "Viking" },
+ { 274, 6, "Núll níu ehf", "Núll níu ehf" },
+ { 274, 7, "IceCell", "IceCell" },
+ { 274, 8, "On-waves", "On-waves" },
+ { 274, 11, "Nova", "Nova" },
+ { 274, 12, "Tal", "Tal" },
+
+ // India - IN
+
+ { 404, 1, "Vodafone IN", "Vodafone IN" },
+ { 404, 2, "AirTel", "AirTel" },
+ { 404, 3, "AirTel", "AirTel" },
+ { 404, 4, "IDEA", "IDEA" },
+ { 404, 5, "Vodafone IN", "Vodafone IN" },
+ { 404, 7, "IDEA", "IDEA" },
+ { 404, 9, "Reliance", "Reliance" },
+ { 404, 10, "AirTel", "AirTel" },
+ { 404, 11, "Vodafone IN", "Vodafone IN" },
+ { 404, 12, "IDEA", "IDEA" },
+ { 404, 13, "Vodafone IN", "Vodafone IN" },
+ { 404, 14, "IDEA", "IDEA" },
+ { 404, 15, "Vodafone IN", "Vodafone IN" },
+ { 404, 16, "Airtel", "Airtel" },
+ { 404, 17, "AIRCEL", "AIRCEL" },
+ { 404, 18, "Reliance", "Reliance" },
+ { 404, 19, "IDEA", "IDEA" },
+ { 404, 20, "Vodafone IN", "Vodafone IN" },
+ { 404, 21, "Loop Mobile", "Loop Mobile" },
+ { 404, 22, "IDEA", "IDEA" },
+ { 404, 24, "IDEA", "IDEA" },
+ { 404, 25, "AIRCEL", "AIRCEL" },
+ { 404, 27, "Vodafone IN", "Vodafone IN" },
+ { 404, 28, "AIRCEL", "AIRCEL" },
+ { 404, 29, "AIRCEL", "AIRCEL" },
+ { 404, 30, "Vodafone IN", "Vodafone IN" },
+ { 404, 31, "AirTel", "AirTel" },
+ { 404, 34, "CellOne", "CellOne" },
+ { 404, 36, "Reliance", "Reliance" },
+ { 404, 37, "Aircel", "Aircel" },
+ { 404, 38, "CellOne", "CellOne" },
+ { 404, 40, "AirTel", "AirTel" },
+ { 404, 41, "Aircel", "Aircel" },
+ { 404, 42, "Aircel", "Aircel" },
+ { 404, 43, "Vodafone IN", "Vodafone IN" },
+ { 404, 44, "IDEA", "IDEA" },
+ { 404, 45, "Airtel", "Airtel" },
+ { 404, 46, "Vodafone IN", "Vodafone IN" },
+ { 404, 48, "Dishnet Wireless", "Dishnet Wireless" },
+ { 404, 49, "Airtel", "Airtel" },
+ { 404, 50, "Reliance", "Reliance" },
+ { 404, 51, "CellOne", "CellOne" },
+ { 404, 52, "Reliance", "Reliance" },
+ { 404, 53, "CellOne", "CellOne" },
+ { 404, 54, "CellOne", "CellOne" },
+ { 404, 55, "CellOne", "CellOne" },
+ { 404, 56, "IDEA", "IDEA" },
+ { 404, 57, "CellOne", "CellOne" },
+ { 404, 58, "CellOne", "CellOne" },
+ { 404, 59, "CellOne", "CellOne" },
+ { 404, 60, "Vodafone IN", "Vodafone IN" },
+ { 404, 62, "CellOne", "CellOne" },
+ { 404, 64, "CellOne", "CellOne" },
+ { 404, 66, "CellOne", "CellOne" },
+ { 404, 67, "Reliance", "Reliance" },
+ { 404, 68, "DOLPHIN", "DOLPHIN" },
+ { 404, 69, "DOLPHIN", "DOLPHIN" },
+ { 404, 70, "AirTel", "AirTel" },
+ { 404, 71, "CellOne", "CellOne" },
+ { 404, 72, "CellOne", "CellOne" },
+ { 404, 73, "CellOne", "CellOne" },
+ { 404, 74, "CellOne", "CellOne" },
+ { 404, 75, "CellOne", "CellOne" },
+ { 404, 76, "CellOne", "CellOne" },
+ { 404, 77, "CellOne", "CellOne" },
+ { 404, 78, "Idea Cellular Ltd", "Idea Cellular Ltd" },
+ { 404, 79, "CellOne", "CellOne" },
+ { 404, 80, "CellOne", "CellOne" },
+ { 404, 81, "CellOne", "CellOne" },
+ { 404, 82, "Idea", "Idea" },
+ { 404, 83, "Reliance", "Reliance" },
+ { 404, 84, "Vodafone IN", "Vodafone IN" },
+ { 404, 85, "Reliance", "Reliance" },
+ { 404, 86, "Vodafone IN", "Vodafone IN" },
+ { 404, 87, "IDEA", "IDEA" },
+ { 404, 88, "Vodafone IN", "Vodafone IN" },
+ { 404, 89, "Idea", "Idea" },
+ { 404, 90, "AirTel", "AirTel" },
+ { 404, 91, "AIRCEL", "AIRCEL" },
+ { 404, 92, "AirTel", "AirTel" },
+ { 404, 93, "AirTel", "AirTel" },
+ { 404, 94, "AirTel", "AirTel" },
+ { 404, 95, "AirTel", "AirTel" },
+ { 404, 96, "AirTel", "AirTel" },
+ { 404, 97, "AirTel", "AirTel" },
+ { 404, 98, "AirTel", "AirTel" },
+ { 405, 1, "Reliance", "Reliance" },
+ { 405, 25, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 26, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 27, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 28, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 29, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 3, "Reliance", "Reliance" },
+ { 405, 30, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 31, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 32, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 33, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 34, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 35, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 36, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 37, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 38, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 39, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 4, "Reliance", "Reliance" },
+ { 405, 41, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 42, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 43, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 44, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 45, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 46, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 47, "TATA DOCOMO", "TATA DOCOMO" },
+ { 405, 5, "Reliance", "Reliance" },
+ { 405, 6, "Reliance", "Reliance" },
+ { 405, 7, "Reliance", "Reliance" },
+ { 405, 8, "Reliance", "Reliance" },
+ { 405, 9, "Reliance", "Reliance" },
+ { 405, 10, "Reliance", "Reliance" },
+ { 405, 11, "Reliance", "Reliance" },
+ { 405, 12, "Reliance", "Reliance" },
+ { 405, 13, "Reliance", "Reliance" },
+ { 405, 14, "Reliance", "Reliance" },
+ { 405, 15, "Reliance", "Reliance" },
+ { 405, 17, "Reliance", "Reliance" },
+ { 405, 18, "Reliance", "Reliance" },
+ { 405, 19, "Reliance", "Reliance" },
+ { 405, 20, "Reliance", "Reliance" },
+ { 405, 21, "Reliance", "Reliance" },
+ { 405, 22, "Reliance", "Reliance" },
+ { 405, 23, "Reliance", "Reliance" },
+ { 405, 51, "AirTel", "AirTel" },
+ { 405, 52, "AirTel", "AirTel" },
+ { 405, 53, "AirTel", "AirTel" },
+ { 405, 54, "AirTel", "AirTel" },
+ { 405, 55, "Airtel", "Airtel" },
+ { 405, 56, "AirTel", "AirTel" },
+ { 405, 66, "Vodafone IN", "Vodafone IN" },
+ { 405, 67, "Vodafone IN", "Vodafone IN" },
+ { 405, 70, "IDEA", "IDEA" },
+ { 405, 750, "Vodafone IN", "Vodafone IN" },
+ { 405, 751, "Vodafone IN", "Vodafone IN" },
+ { 405, 752, "Vodafone IN", "Vodafone IN" },
+ { 405, 753, "Vodafone IN", "Vodafone IN" },
+ { 405, 754, "Vodafone IN", "Vodafone IN" },
+ { 405, 755, "Vodafone IN", "Vodafone IN" },
+ { 405, 756, "Vodafone IN", "Vodafone IN" },
+ { 405, 799, "IDEA", "IDEA" },
+ { 405, 800, "AIRCEL", "AIRCEL" },
+ { 405, 801, "AIRCEL", "AIRCEL" },
+ { 405, 802, "AIRCEL", "AIRCEL" },
+ { 405, 803, "AIRCEL", "AIRCEL" },
+ { 405, 804, "AIRCEL", "AIRCEL" },
+ { 405, 805, "AIRCEL", "AIRCEL" },
+ { 405, 806, "AIRCEL", "AIRCEL" },
+ { 405, 807, "AIRCEL", "AIRCEL" },
+ { 405, 808, "AIRCEL", "AIRCEL" },
+ { 405, 809, "AIRCEL", "AIRCEL" },
+ { 405, 810, "AIRCEL", "AIRCEL" },
+ { 405, 811, "AIRCEL", "AIRCEL" },
+ { 405, 812, "AIRCEL", "AIRCEL" },
+ { 405, 819, "Uninor", "Uninor" },
+ { 405, 818, "Uninor", "Uninor" },
+ { 405, 820, "Uninor", "Uninor" },
+ { 405, 821, "Uninor", "Uninor" },
+ { 405, 822, "Uninor", "Uninor" },
+ { 405, 824, "Videocon Datacom", "Videocon Datacom" },
+ { 405, 827, "Videocon Datacom", "Videocon Datacom" },
+ { 405, 834, "Videocon Datacom", "Videocon Datacom" },
+ { 405, 844, "Uninor", "Uninor" },
+ { 405, 840, "Jio", "Jio" },
+ { 405, 845, "IDEA", "IDEA" },
+ { 405, 846, "IDEA", "IDEA" },
+ { 405, 847, "IDEA", "IDEA" },
+ { 405, 848, "IDEA", "IDEA" },
+ { 405, 849, "IDEA", "IDEA" },
+ { 405, 850, "IDEA", "IDEA" },
+ { 405, 851, "IDEA", "IDEA" },
+ { 405, 852, "IDEA", "IDEA" },
+ { 405, 853, "IDEA", "IDEA" },
+ { 405, 854, "Jio", "Jio" },
+ { 405, 855, "Jio", "Jio" },
+ { 405, 856, "Jio", "Jio" },
+ { 405, 857, "Jio", "Jio" },
+ { 405, 858, "Jio", "Jio" },
+ { 405, 859, "Jio", "Jio" },
+ { 405, 860, "Jio", "Jio" },
+ { 405, 861, "Jio", "Jio" },
+ { 405, 862, "Jio", "Jio" },
+ { 405, 863, "Jio", "Jio" },
+ { 405, 864, "Jio", "Jio" },
+ { 405, 865, "Jio", "Jio" },
+ { 405, 866, "Jio", "Jio" },
+ { 405, 867, "Jio", "Jio" },
+ { 405, 868, "Jio", "Jio" },
+ { 405, 869, "Jio", "Jio" },
+ { 405, 870, "Jio", "Jio" },
+ { 405, 871, "Jio", "Jio" },
+ { 405, 872, "Jio", "Jio" },
+ { 405, 873, "Jio", "Jio" },
+ { 405, 874, "Jio", "Jio" },
+ { 405, 875, "Uninor", "Uninor" },
+ { 405, 880, "Uninor", "Uninor" },
+ { 405, 881, "S Tel", "S Tel" },
+ { 405, 908, "IDEA", "IDEA" },
+ { 405, 909, "IDEA", "IDEA" },
+ { 405, 910, "IDEA", "IDEA" },
+ { 405, 911, "IDEA", "IDEA" },
+ { 405, 912, "Etisalat DB(cheers)", "Etisalat DB(cheers)" },
+ { 405, 913, "Etisalat DB(cheers)", "Etisalat DB(cheers)" },
+ { 405, 914, "Etisalat DB(cheers)", "Etisalat DB(cheers)" },
+ { 405, 917, "Etisalat DB(cheers)", "Etisalat DB(cheers)" },
+ { 405, 927, "Uninor", "Uninor" },
+ { 405, 929, "Uninor", "Uninor" },
+
+ // Indonesia - ID
+
+ { 510, 1, "INDOSAT", "INDOSAT" },
+ { 510, 3, "StarOne", "StarOne" },
+ { 510, 7, "TelkomFlexi", "TelkomFlexi" },
+ { 510, 8, "AXIS", "AXIS" },
+ { 510, 9, "SMARTFREN", "SMARTFREN" },
+ { 510, 10, "Telkomsel", "Telkomsel" },
+ { 510, 11, "XL", "XL" },
+ { 510, 20, "TELKOMMobile", "TELKOMMobile" },
+ { 510, 21, "IM3", "IM3" },
+ { 510, 27, "Ceria", "Ceria" },
+ { 510, 28, "Fren/Hepi", "Fren/Hepi" },
+ { 510, 89, "3", "3" },
+ { 510, 99, "Esia", "Esia" },
+ { 510, 995, "Komselindo", "Komselindo" },
+ { 510, 996, "Komselindo", "Komselindo" },
+
+ // Iran - IR
+
+ { 432, 11, "IR-MCI", "IR-MCI" },
+ { 432, 14, "TKC", "TKC" },
+ { 432, 19, "MTCE", "MTCE" },
+ { 432, 20, "Rightel", "Rightel" },
+ { 432, 32, "Taliya", "Taliya" },
+ { 432, 35, "Irancell", "Irancell" },
+ { 432, 70, "TCI", "TCI" },
+ { 432, 93, "Iraphone", "Iraphone" },
+
+ // Iraq - IQ
+
+ { 418, 5, "Asia Cell", "Asia Cell" },
+ { 418, 8, "SanaTel", "SanaTel" },
+ { 418, 20, "Zain", "Zain" },
+ { 418, 30, "Zain", "Zain" },
+ { 418, 40, "Korek", "Korek" },
+ { 418, 45, "Mobitel", "Mobitel" },
+ { 418, 62, "Itisaluna", "Itisaluna" },
+ { 418, 92, "Omnnea", "Omnnea" },
+
+ // Ireland - IE
+
+ { 272, 1, "Vodafone", "Vodafone" },
+ { 272, 2, "O2", "O2" },
+ { 272, 3, "Meteor", "Meteor" },
+ { 272, 4, "Access Telecom", "Access Telecom" },
+ { 272, 5, "3", "3" },
+ { 272, 7, "eMobile", "eMobile" },
+ { 272, 9, "Clever Communications", "Clever Communications" },
+ { 272, 11, "Tesco Mobile", "Tesco Mobile" },
+ { 272, 13, "Lycamobile", "Lycamobile" },
+
+ // Isle of Man (United Kingdom) - IM
+
+ { 234, 9, "Sure Mobile", "Sure Mobile" },
+ { 234, 58, "Pronto GSM", "Pronto GSM" },
+
+ // Israel - IL
+
+ { 425, 1, "Orange", "Orange" },
+ { 425, 2, "Cellcom", "Cellcom" },
+ { 425, 3, "Pelephone", "Pelephone" },
+ { 425, 7, "Hot Mobile", "Hot Mobile" },
+ { 425, 8, "Golan Telecom", "Golan Telecom" },
+ { 425, 11, "365 Telecom", "365 Telecom" },
+ { 425, 12, "Free Telecom", "Free Telecom" },
+ { 425, 13, "Ituran Cellular Communications", "Ituran Cellular Communications" },
+ { 425, 14, "Youphone", "Youphone" },
+ { 425, 15, "Home Cellular", "Home Cellular" },
+ { 425, 16, "Rami Levy", "Rami Levy" },
+ { 425, 17, "Gale Phone", "Gale Phone" },
+ { 425, 18, "Cellact Communications", "Cellact Communications" },
+ { 425, 19, "Azi Communications Ltd.", "Azi Communications Ltd." },
+ { 425, 20, "Bezeq Ltd", "Bezeq Ltd" },
+ { 425, 21, "B.I.P. Communications Ltd.", "B.I.P. Communications Ltd." },
+
+ // Italy - IT
+
+ { 222, 1, "TIM", "TIM" },
+ { 222, 2, "Elsacom", "Elsacom" },
+ { 222, 4, "Intermatica", "Intermatica" },
+ { 222, 5, "Telespazio", "Telespazio" },
+ { 222, 7, "Noverca", "Noverca" },
+ { 222, 10, "Vodafone", "Vodafone" },
+ { 222, 30, "RFI", "RFI" },
+ { 222, 34, "BT Italia", "BT Italia" },
+ { 222, 35, "Lyca Italy", "Lyca Italy" },
+ { 222, 77, "IPSE 2000", "IPSE 2000" },
+ { 222, 88, "Wind", "Wind" },
+ { 222, 98, "Blu", "Blu" },
+ { 222, 99, "3 Italia", "3 Italia" },
+
+ // Ivory Coast - CI
+
+ { 612, 1, "Cora de Comstar", "Cora de Comstar" },
+ { 612, 2, "Moov", "Moov" },
+ { 612, 3, "Orange", "Orange" },
+ { 612, 4, "KoZ", "KoZ" },
+ { 612, 5, "MTN", "MTN" },
+ { 612, 6, "ORICEL", "ORICEL" },
+
+ // Jamaica - JM
+
+ { 338, 20, "LIME", "LIME" },
+ { 338, 50, "Digicel", "Digicel" },
+ { 338, 110, "LIME", "LIME" },
+ { 338, 180, "LIME", "LIME" },
+
+ // Japan - JP
+
+ { 440, 1, "NTT docomo", "NTT docomo" },
+ { 440, 2, "NTT docomo", "NTT docomo" },
+ { 440, 3, "NTT docomo", "NTT docomo" },
+ { 440, 4, "SoftBank", "SoftBank" },
+ { 440, 6, "SoftBank", "SoftBank" },
+ { 440, 7, "KDDI", "KDDI" },
+ { 440, 8, "KDDI", "KDDI" },
+ { 440, 9, "NTT docomo", "NTT docomo" },
+ { 440, 10, "NTT docomo", "NTT docomo" },
+ { 440, 11, "NTT docomo", "NTT docomo" },
+ { 440, 12, "NTT docomo", "NTT docomo" },
+ { 440, 13, "NTT docomo", "NTT docomo" },
+ { 440, 14, "NTT docomo", "NTT docomo" },
+ { 440, 15, "NTT docomo", "NTT docomo" },
+ { 440, 16, "NTT docomo", "NTT docomo" },
+ { 440, 17, "NTT docomo", "NTT docomo" },
+ { 440, 18, "NTT docomo", "NTT docomo" },
+ { 440, 19, "NTT docomo", "NTT docomo" },
+ { 440, 20, "SoftBank", "SoftBank" },
+ { 440, 21, "NTT docomo", "NTT docomo" },
+ { 440, 22, "NTT docomo", "NTT docomo" },
+ { 440, 23, "NTT docomo", "NTT docomo" },
+ { 440, 24, "NTT docomo", "NTT docomo" },
+ { 440, 25, "NTT docomo", "NTT docomo" },
+ { 440, 26, "NTT docomo", "NTT docomo" },
+ { 440, 27, "NTT docomo", "NTT docomo" },
+ { 440, 28, "NTT docomo", "NTT docomo" },
+ { 440, 29, "NTT docomo", "NTT docomo" },
+ { 440, 30, "NTT docomo", "NTT docomo" },
+ { 440, 31, "NTT docomo", "NTT docomo" },
+ { 440, 32, "NTT docomo", "NTT docomo" },
+ { 440, 33, "NTT docomo", "NTT docomo" },
+ { 440, 34, "NTT docomo", "NTT docomo" },
+ { 440, 35, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 36, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 37, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 38, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 39, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 40, "SoftBank", "SoftBank" },
+ { 440, 41, "SoftBank", "SoftBank" },
+ { 440, 42, "SoftBank", "SoftBank" },
+ { 440, 43, "SoftBank", "SoftBank" },
+ { 440, 44, "SoftBank", "SoftBank" },
+ { 440, 45, "SoftBank", "SoftBank" },
+ { 440, 46, "SoftBank", "SoftBank" },
+ { 440, 47, "SoftBank", "SoftBank" },
+ { 440, 48, "SoftBank", "SoftBank" },
+ { 440, 49, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 50, "KDDI", "KDDI" },
+ { 440, 51, "KDDI", "KDDI" },
+ { 440, 52, "KDDI", "KDDI" },
+ { 440, 53, "KDDI", "KDDI" },
+ { 440, 54, "KDDI", "KDDI" },
+ { 440, 55, "KDDI", "KDDI" },
+ { 440, 56, "KDDI", "KDDI" },
+ { 440, 58, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 60, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 61, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 62, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 63, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 64, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 65, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 66, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 67, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 68, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 69, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 70, "au", "au" },
+ { 440, 71, "KDDI", "KDDI" },
+ { 440, 72, "KDDI", "KDDI" },
+ { 440, 73, "KDDI", "KDDI" },
+ { 440, 74, "KDDI", "KDDI" },
+ { 440, 75, "KDDI", "KDDI" },
+ { 440, 76, "KDDI", "KDDI" },
+ { 440, 77, "KDDI", "KDDI" },
+ { 440, 78, "Okinawa Cellular Telephone", "Okinawa Cellular Telephone" },
+ { 440, 79, "KDDI", "KDDI" },
+ { 440, 80, "TU-KA", "TU-KA" },
+ { 440, 81, "TU-KA", "TU-KA" },
+ { 440, 82, "TU-KA", "TU-KA" },
+ { 440, 83, "TU-KA", "TU-KA" },
+ { 440, 84, "TU-KA", "TU-KA" },
+ { 440, 85, "TU-KA", "TU-KA" },
+ { 440, 86, "TU-KA", "TU-KA" },
+ { 440, 87, "NTT DoCoMo", "NTT DoCoMo" },
+ { 440, 88, "KDDI", "KDDI" },
+ { 440, 89, "KDDI", "KDDI" },
+ { 440, 90, "SoftBank", "SoftBank" },
+ { 440, 92, "SoftBank", "SoftBank" },
+ { 440, 93, "SoftBank", "SoftBank" },
+ { 440, 94, "SoftBank", "SoftBank" },
+ { 440, 95, "SoftBank", "SoftBank" },
+ { 440, 96, "SoftBank", "SoftBank" },
+ { 440, 97, "SoftBank", "SoftBank" },
+ { 440, 98, "SoftBank", "SoftBank" },
+ { 440, 99, "NTT DoCoMo", "NTT DoCoMo" },
+
+ // Jersey (United Kingdom) - JE
+
+ { 234, 3, "Airtel Vodafone", "Airtel Vodafone" },
+ { 234, 50, "JT", "JT" },
+ { 234, 55, "Sure Mobile", "Sure Mobile" },
+
+ // Jordan - JO
+
+ { 416, 1, "zain JO", "zain JO" },
+ { 416, 2, "XPress Telecom", "XPress Telecom" },
+ { 416, 3, "Umniah", "Umniah" },
+ { 416, 77, "Orange", "Orange" },
+
+ // Kazakhstan - KZ
+
+ { 401, 1, "Beeline", "Beeline" },
+ { 401, 2, "Kcell", "Kcell" },
+ { 401, 7, "Dalacom", "Dalacom" },
+ { 401, 8, "Kazakhtelecom", "Kazakhtelecom" },
+ { 401, 77, "Tele2.kz", "Tele2.kz" },
+
+ // Kenya - KE
+
+ { 639, 2, "Safaricom", "Safaricom" },
+ { 639, 3, "Airtel", "Airtel" },
+ { 639, 5, "yu", "yu" },
+ { 639, 7, "Orange Kenya", "Orange Kenya" },
+
+ // Kiribati - KI
+
+ { 545, 1, "Kiribati - TSKL", "Kiribati - TSKL" },
+ { 545, 9, "Kiribati - Frigate Net", "Kiribati - Frigate Net" },
+
+ // North Korea - KP
+
+ { 467, 5, "Koryolink", "Koryolink" },
+ { 467, 193, "SunNet", "SunNet" },
+
+ // South Korea - KR
+
+ { 450, 2, "KT", "KT" },
+ { 450, 3, "Power 017", "Power 017" },
+ { 450, 4, "KT", "KT" },
+ { 450, 5, "SKTelecom", "SKTelecom" },
+ { 450, 6, "LG U+", "LG U+" },
+ { 450, 8, "olleh", "olleh" },
+ { 450, 11, "SKTelecom", "SKTelecom" },
+
+ // Kosovo - XK
+
+ { 212, 1, "Vala", "Vala" },
+ { 212, 1, "Z Mobile", "Z Mobile" },
+ { 293, 41, "IPKO", "IPKO" },
+ { 293, 41, "D3 Mobile", "D3 Mobile" },
+
+ // Kuwait - KW
+
+ { 419, 2, "zain KW", "zain KW" },
+ { 419, 3, "Wataniya", "Wataniya" },
+ { 419, 4, "Viva", "Viva" },
+
+ // Kyrgyzstan - KG
+
+ { 437, 1, "Beeline", "Beeline" },
+ { 437, 3, "Fonex", "Fonex" },
+ { 437, 5, "MegaCom", "MegaCom" },
+ { 437, 9, "O!", "O!" },
+
+ // Laos - LA
+
+ { 457, 1, "LTC", "LTC" },
+ { 457, 2, "ETL", "ETL" },
+ { 457, 3, "Unitel", "Unitel" },
+ { 457, 8, "Beeline", "Beeline" },
+
+ // Latvia - LV
+
+ { 247, 1, "LMT", "LMT" },
+ { 247, 2, "Tele2", "Tele2" },
+ { 247, 3, "TRIATEL", "TRIATEL" },
+ { 247, 4, "Beta Telecom", "Beta Telecom" },
+ { 247, 5, "Bite", "Bite" },
+ { 247, 6, "Rigatta", "Rigatta" },
+ { 247, 7, "MTS", "MTS" },
+ { 247, 8, "IZZI", "IZZI" },
+ { 247, 9, "Camel Mobile", "Camel Mobile" },
+
+ // Lebanon - LB
+
+ { 415, 1, "Alfa", "Alfa" },
+ { 415, 3, "mtc touch", "mtc touch" },
+ { 415, 5, "Ogero Mobile", "Ogero Mobile" },
+
+ // Lesotho - LS
+
+ { 651, 1, "Vodacom", "Vodacom" },
+ { 651, 2, "Econet Ezi-cel", "Econet Ezi-cel" },
+
+ // Liberia - LR
+
+ { 618, 1, "Lonestar Cell", "Lonestar Cell" },
+ { 618, 2, "Libercell", "Libercell" },
+ { 618, 4, "Comium", "Comium" },
+ { 618, 7, "Cellcom", "Cellcom" },
+ { 618, 20, "LIBTELCO", "LIBTELCO" },
+
+ // Libya - LY
+
+ { 606, 1, "Madar", "Madar" },
+ { 606, 2, "Al-Jeel Phone", "Al-Jeel Phone" },
+ { 606, 3, "Libya Phone", "Libya Phone" },
+ { 606, 6, "Hatef Libya", "Hatef Libya" },
+
+ // Liechtenstein - LI
+
+ { 295, 1, "Swisscom", "Swisscom" },
+ { 295, 2, "Orange", "Orange" },
+ { 295, 5, "FL1", "FL1" },
+ { 295, 6, "Cubic Telecom", "Cubic Telecom" },
+ { 295, 77, "Alpmobil", "Alpmobil" },
+
+ // Lithuania - LT
+
+ { 246, 1, "Omnitel", "Omnitel" },
+ { 246, 2, "BITĖ", "BITĖ" },
+ { 246, 3, "Tele 2", "Tele 2" },
+ { 246, 5, "LitRail", "LitRail" },
+ { 246, 6, "Mediafon", "Mediafon" },
+
+ // Luxembourg - LU
+
+ { 270, 1, "POST", "POST" },
+ { 270, 2, "MTX Connect S.a.r.l.", "MTX Connect S.a.r.l." },
+ { 270, 10, "Blue Communications", "Blue Communications" },
+ { 270, 77, "Tango", "Tango" },
+ { 270, 78, "Interactive digital media GmbH", "Interactive digital media GmbH" },
+ { 270, 99, "Orange", "Orange" },
+
+ // Macau (People's Republic of China) - MO
+
+ { 455, 1, "CTM", "CTM" },
+ { 455, 2, "China Telecom", "China Telecom" },
+ { 455, 3, "3", "3" },
+ { 455, 4, "CTM", "CTM" },
+ { 455, 5, "3", "3" },
+ { 455, 6, "SmarTone", "SmarTone" },
+
+ // Macedonia - MK
+
+ { 294, 1, "T-Mobile MK", "T-Mobile MK" },
+ { 294, 2, "ONE", "ONE" },
+ { 294, 3, "Vip MK", "Vip MK" },
+
+ // Madagascar - MG
+
+ { 646, 1, "Airtel", "Airtel" },
+ { 646, 2, "Orange", "Orange" },
+ { 646, 3, "Sacel", "Sacel" },
+ { 646, 4, "Telma", "Telma" },
+
+ // Malawi - MW
+
+ { 650, 1, "TNM", "TNM" },
+ { 650, 10, "Airtel", "Airtel" },
+
+ // Malaysia - MY
+
+ { 502, 1, "ATUR 450", "ATUR 450" },
+ { 502, 10, "DiGi Telecommunications", "DiGi Telecommunications" },
+ { 502, 11, "TM Homeline", "TM Homeline" },
+ { 502, 12, "Maxis", "Maxis" },
+ { 502, 13, "Celcom", "Celcom" },
+ { 502, 14, "Telekom Malaysia Berhad for PSTN SMS", "Telekom Malaysia Berhad for PSTN SMS" },
+ { 502, 150, "Tune Talk", "Tune Talk" },
+ { 502, 151, "Baraka Telecom Sdn Bhd (MVNE)", "Baraka Telecom Sdn Bhd (MVNE)" },
+ { 502, 152, "Yes", "Yes" },
+ { 502, 156, "Altel", "Altel" },
+ { 502, 16, "DiGi", "DiGi" },
+ { 502, 17, "Hotlink", "Hotlink" },
+ { 502, 18, "U Mobile", "U Mobile" },
+ { 502, 18, "TM Homeline", "TM Homeline" },
+ { 502, 19, "Celcom", "Celcom" },
+ { 502, 20, "Electcoms Wireless Sdn Bhd", "Electcoms Wireless Sdn Bhd" },
+ { 502, 12, "Kartu As", "Kartu As" },
+
+ // Maldives - MV
+
+ { 472, 1, "Dhiraagu", "Dhiraagu" },
+ { 472, 2, "Ooredoo", "Ooredoo" },
+
+ // Mali - ML
+
+ { 610, 1, "Malitel", "Malitel" },
+ { 610, 2, "Orange", "Orange" },
+
+ // Malta - MT
+
+ { 278, 1, "Vodafone", "Vodafone" },
+ { 278, 21, "GO", "GO" },
+ { 278, 77, "Melita", "Melita" },
+
+ // Marshall Islands - MH
+
+ { 551, 1, "Marshall Islands National Telecommunications Authority (MINTA)", "Marshall Islands National Telecommunications Authority (MINTA)" },
+
+ // Martinique (France) - MQ
+
+ { 340, 1, "Orange", "Orange" },
+ { 340, 2, "Outremer", "Outremer" },
+ { 340, 20, "Digicel", "Digicel" },
+
+ // Mauritania - MR
+
+ { 609, 1, "Mattel", "Mattel" },
+ { 609, 2, "Chinguitel", "Chinguitel" },
+ { 609, 10, "Mauritel", "Mauritel" },
+
+ // Mauritius - MU
+
+ { 617, 1, "Orange", "Orange" },
+ { 617, 2, "MTML", "MTML" },
+ { 617, 10, "Emtel", "Emtel" },
+
+ // Mayotte (France) - YT
+
+
+ // Mexico - MX
+
+ { 334, 10, "Nextel", "Nextel" },
+ { 334, 20, "Telcel", "Telcel" },
+ { 334, 30, "movistar", "movistar" },
+ { 334, 30, "Virgin Mobile", "Virgin Mobile" },
+ { 334, 40, "Iusacell / Unefon", "Iusacell / Unefon" },
+ { 334, 50, "Iusacell", "Iusacell" },
+ { 334, 90, "Nextel", "Nextel" },
+
+ // Federated States of Micronesia - FM
+
+ { 550, 1, "FSMTC", "FSMTC" },
+
+ // Moldova - MD
+
+ { 259, 1, "Orange", "Orange" },
+ { 259, 2, "Moldcell", "Moldcell" },
+ { 259, 3, "IDC", "IDC" },
+ { 259, 3, "Unité", "Unité" },
+ { 259, 4, "Eventis", "Eventis" },
+ { 259, 5, "Unité", "Unité" },
+ { 259, 99, "Unité", "Unité" },
+
+ // Monaco - MC
+
+ { 212, 1, "Office des Telephones", "Office des Telephones" },
+
+ // Mongolia - MN
+
+ { 428, 88, "Unitel", "Unitel" },
+ { 428, 91, "Skytel", "Skytel" },
+ { 428, 98, "G.Mobile", "G.Mobile" },
+ { 428, 99, "MobiCom", "MobiCom" },
+
+ // Montenegro - ME
+
+ { 297, 1, "Telenor", "Telenor" },
+ { 297, 2, "T-Mobile", "T-Mobile" },
+ { 297, 3, "m:tel CG", "m:tel CG" },
+ { 297, 4, "T-Mobile", "T-Mobile" },
+
+ // Montserrat (United Kingdom) - MS
+
+ { 354, 860, "Cable & Wireless", "Cable & Wireless" },
+
+ // Morocco - MA
+
+ { 604, 1, "IAM", "IAM" },
+ { 604, 2, "Wana Corporate", "Wana Corporate" },
+ { 604, 5, "INWI", "INWI" },
+
+ // Mozambique - MZ
+
+ { 643, 1, "mCel", "mCel" },
+ { 643, 3, "Movitel", "Movitel" },
+ { 643, 4, "Vodacom", "Vodacom" },
+
+ // Myanmar - MM
+
+ { 414, 1, "MPT", "MPT" },
+ { 414, 5, "Ooredoo", "Ooredoo" },
+ { 414, 6, "NA", "NA" },
+
+ // Namibia - NA
+
+ { 649, 1, "MTC", "MTC" },
+ { 649, 2, "switch", "switch" },
+ { 649, 3, "TN Mobile", "TN Mobile" },
+
+ // Nauru - NR
+
+ { 536, 2, "Digicel", "Digicel" },
+
+ // Nepal - NP
+
+ { 429, 1, "Namaste / NT Mobile", "Namaste / NT Mobile" },
+ { 429, 2, "Ncell", "Ncell" },
+ { 429, 3, "Sky/C-Phone", "Sky/C-Phone" },
+ { 429, 4, "SmartCell", "SmartCell" },
+
+ // Netherlands (Kingdom of the Netherlands) - NL
+
+ { 204, 1, "RadioAccess Network Services BV", "RadioAccess Network Services BV" },
+ { 204, 2, "Tele2", "Tele2" },
+ { 204, 3, "Voiceworks", "Voiceworks" },
+ { 204, 4, "Vodafone", "Vodafone" },
+ { 204, 5, "Elephant Talk Communications Premium Rate Services", "Elephant Talk Communications Premium Rate Services" },
+ { 204, 6, "Vectone Mobile Delight Mobile", "Vectone Mobile Delight Mobile" },
+ { 204, 7, "Teleena (MVNE)", "Teleena (MVNE)" },
+ { 204, 8, "KPN", "KPN" },
+ { 204, 9, "Lycamobile", "Lycamobile" },
+ { 204, 10, "KPN", "KPN" },
+ { 204, 11, "VoipIT B.V.", "VoipIT B.V." },
+ { 204, 12, "Telfort", "Telfort" },
+ { 204, 13, "Unica Installatietechniek B.V.", "Unica Installatietechniek B.V." },
+ { 204, 14, "6GMOBILE B.V.", "6GMOBILE B.V." },
+ { 204, 15, "Ziggo", "Ziggo" },
+ { 204, 16, "T-Mobile (BEN)", "T-Mobile (BEN)" },
+ { 204, 17, "Intercity Zakelijk", "Intercity Zakelijk" },
+ { 204, 18, "UPC Nederland B.V.", "UPC Nederland B.V." },
+ { 204, 19, "Mixe Communication Solutions B.V.", "Mixe Communication Solutions B.V." },
+ { 204, 20, "T-Mobile", "T-Mobile" },
+ { 204, 21, "ProRail B.V.", "ProRail B.V." },
+ { 204, 22, "Ministerie van Defensie", "Ministerie van Defensie" },
+ { 204, 23, "ASPIDER Solutions Nederland B.V.", "ASPIDER Solutions Nederland B.V." },
+ { 204, 24, "Private Mobility Nederland B.V.", "Private Mobility Nederland B.V." },
+ { 204, 25, "CapX B.V.", "CapX B.V." },
+ { 204, 26, "SpeakUp B.V.", "SpeakUp B.V." },
+ { 204, 27, "Breezz Nederland B.V.", "Breezz Nederland B.V." },
+ { 204, 28, "Lancelot B.V.", "Lancelot B.V." },
+ { 204, 60, "Nextgen Mobile Ltd", "Nextgen Mobile Ltd" },
+ { 204, 61, "BodyTrace Netherlands B.V.", "BodyTrace Netherlands B.V." },
+ { 204, 62, "Voxbone", "Voxbone" },
+ { 204, 64, "Zetacom B.V.", "Zetacom B.V." },
+ { 204, 65, "AGMS Netherlands B.V.", "AGMS Netherlands B.V." },
+ { 204, 66, "Utility Connect B.V.", "Utility Connect B.V." },
+ { 204, 67, "RadioAccess B.V.", "RadioAccess B.V." },
+ { 204, 68, "Roamware (Netherlands) B.V.", "Roamware (Netherlands) B.V." },
+ { 204, 69, "KPN Mobile The Netherlands B.V.", "KPN Mobile The Netherlands B.V." },
+
+ // Former Netherlands Antilles (Kingdom of the Netherlands) - AN
+
+ { 362, 51, "Telcell", "Telcell" },
+ { 362, 69, "Digicel", "Digicel" },
+ { 362, 91, "UTS", "UTS" },
+ { 362, 94, "Bayòs", "Bayòs" },
+ { 362, 95, "MIO", "MIO" },
+
+ // New Caledonia (France) - NC
+
+ { 546, 1, "Mobilis", "Mobilis" },
+
+ // New Zealand - NZ
+
+ { 530, 1, "Vodafone", "Vodafone" },
+ { 530, 2, "Telecom", "Telecom" },
+ { 530, 3, "Woosh", "Woosh" },
+ { 530, 4, "TelstraClear", "TelstraClear" },
+ { 530, 5, "XT Mobile Network", "XT Mobile Network" },
+ { 530, 6, "Skinny", "Skinny" },
+ { 530, 24, "2degrees", "2degrees" },
+
+ // Nicaragua - NI
+
+ { 710, 21, "Claro", "Claro" },
+ { 710, 30, "movistar", "movistar" },
+ { 710, 73, "SERCOM", "SERCOM" },
+
+ // Niger - NE
+
+ { 614, 1, "SahelCom", "SahelCom" },
+ { 614, 2, "Airtel", "Airtel" },
+ { 614, 3, "Moov", "Moov" },
+ { 614, 4, "Orange", "Orange" },
+
+ // Nigeria - NG
+
+ { 621, 20, "Airtel", "Airtel" },
+ { 621, 25, "Visafone", "Visafone" },
+ { 621, 30, "MTN", "MTN" },
+ { 621, 40, "M-Tel", "M-Tel" },
+ { 621, 50, "Glo", "Glo" },
+ { 621, 60, "Etisalat", "Etisalat" },
+
+ // Niue - NU
+
+ { 555, 1, "Telecom Niue", "Telecom Niue" },
+
+ // Norfolk Island - NF
+
+ { 505, 10, "Norfolk Telecom", "Norfolk Telecom" },
+
+ // Northern Mariana Islands - MP
+
+
+ // Norway - NO
+
+ { 242, 1, "Telenor", "Telenor" },
+ { 242, 2, "NetCom", "NetCom" },
+ { 242, 3, "Teletopia", "Teletopia" },
+ { 242, 4, "Tele2", "Tele2" },
+ { 242, 5, "Network Norway", "Network Norway" },
+ { 242, 6, "Ice", "Ice" },
+ { 242, 7, "Ventelo", "Ventelo" },
+ { 242, 8, "TDC", "TDC" },
+ { 242, 9, "Com4", "Com4" },
+ { 242, 11, "SystemNet", "SystemNet" },
+ { 242, 12, "Telenor", "Telenor" },
+ { 242, 20, "Jernbaneverket AS", "Jernbaneverket AS" },
+ { 242, 21, "Jernbaneverket AS", "Jernbaneverket AS" },
+ { 242, 23, "Lyca", "Lyca" },
+ { 242, 24, "Mobile Norway AS", "Mobile Norway AS" },
+
+ // Oman - OM
+
+ { 422, 2, "Oman Mobile", "Oman Mobile" },
+ { 422, 3, "Nawras", "Nawras" },
+
+ // Pakistan - PK
+
+ { 410, 1, "Mobilink", "Mobilink" },
+ { 410, 3, "Ufone", "Ufone" },
+ { 410, 4, "Zong", "Zong" },
+ { 410, 5, "SCO Mobile", "SCO Mobile" },
+ { 410, 6, "Telenor", "Telenor" },
+ { 410, 7, "Warid Pakistan", "Warid Pakistan" },
+
+ // Palau - PW
+
+ { 552, 1, "PNCC", "PNCC" },
+ { 552, 80, "Palau Mobile", "Palau Mobile" },
+
+ // Palestine, State of - PS
+
+ { 425, 5, "Jawwal", "Jawwal" },
+ { 425, 6, "Wataniya", "Wataniya" },
+
+ // Panama - PA
+
+ { 714, 1, "Cable & Wireless", "Cable & Wireless" },
+ { 714, 2, "movistar", "movistar" },
+ { 714, 3, "Claro", "Claro" },
+ { 714, 4, "Digicel", "Digicel" },
+
+ // Papua New Guinea - PG
+
+ { 537, 1, "bmobile", "bmobile" },
+ { 537, 3, "Digicel", "Digicel" },
+
+ // Paraguay - PY
+
+ { 744, 1, "VOX", "VOX" },
+ { 744, 2, "Claro/Hutchison", "Claro/Hutchison" },
+ { 744, 4, "Tigo", "Tigo" },
+ { 744, 5, "Personal", "Personal" },
+ { 744, 6, "Copaco", "Copaco" },
+
+ // Peru - PE
+
+ { 716, 6, "Movistar", "Movistar" },
+ { 716, 7, "NEXTEL", "NEXTEL" },
+ { 716, 10, "Claro (TIM)", "Claro (TIM)" },
+ { 716, 15, "Viettel Mobile", "Viettel Mobile" },
+ { 716, 17, "NEXTEL", "NEXTEL" },
+
+ // Philippines - PH
+
+ { 515, 1, "Islacom", "Islacom" },
+ { 515, 2, "Globe", "Globe" },
+ { 515, 3, "Smart", "Smart" },
+ { 515, 5, "Sun", "Sun" },
+ { 515, 11, "PLDT via ACeS Philippines", "PLDT via ACeS Philippines" },
+ { 515, 18, "Cure", "Cure" },
+ { 515, 24, "ABS-CBN", "ABS-CBN" },
+ { 515, 88, "Nextel", "Nextel" },
+
+ // Pitcairn Islands (United Kingdom) - PN
+
+
+ // Poland - PL
+
+ { 260, 1, "Plus", "Plus" },
+ { 260, 2, "T-Mobile", "T-Mobile" },
+ { 260, 3, "Orange", "Orange" },
+ { 260, 4, "CenterNet S.A.", "CenterNet S.A." },
+ { 260, 5, "Polska Telefonia Komórkowa Centertel Sp. z o.o.", "Polska Telefonia Komórkowa Centertel Sp. z o.o." },
+ { 260, 6, "Play", "Play" },
+ { 260, 7, "Netia", "Netia" },
+ { 260, 8, "E-Telko Sp. z o.o.", "E-Telko Sp. z o.o." },
+ { 260, 9, "Lycamobile", "Lycamobile" },
+ { 260, 10, "Sferia", "Sferia" },
+ { 260, 11, "Nordisk Polska", "Nordisk Polska" },
+ { 260, 12, "Cyfrowy Polsat", "Cyfrowy Polsat" },
+ { 260, 13, "Sferia", "Sferia" },
+ { 260, 14, "Sferia", "Sferia" },
+ { 260, 15, "CenterNet", "CenterNet" },
+ { 260, 16, "Mobyland", "Mobyland" },
+ { 260, 17, "Aero2", "Aero2" },
+ { 260, 32, "Voxbone", "Voxbone" },
+ { 260, 34, "T-Mobile Polska S.A.", "T-Mobile Polska S.A." },
+ { 260, 98, "P4 Sp. z o.o.", "P4 Sp. z o.o." },
+
+ // Portugal - PT
+
+ { 268, 1, "Vodafone", "Vodafone" },
+ { 268, 3, "Optimus", "Optimus" },
+ { 268, 4, "LycaMobile", "LycaMobile" },
+ { 268, 6, "TMN", "TMN" },
+ { 268, 7, "Vectonemobile - Delightmobile", "Vectonemobile - Delightmobile" },
+ { 268, 21, "Zapp", "Zapp" },
+
+ // Puerto Rico - PR
+
+ { 330, 110, "Claro Puerto Rico", "Claro Puerto Rico" },
+ { 330, 120, "tmobile", "tmobile" },
+
+ // Qatar - QA
+
+ { 427, 1, "ooredoo", "ooredoo" },
+ { 427, 2, "Vodafone", "Vodafone" },
+ { 427, 5, "Ministry of Interior", "Ministry of Interior" },
+ { 427, 6, "Ministry of Interior", "Ministry of Interior" },
+
+ // Réunion (France) - RE
+
+ { 647, 1, "BJT Partners", "BJT Partners" },
+ { 647, 2, "Outremer", "Outremer" },
+ { 647, 10, "SFR Reunion", "SFR Reunion" },
+
+ // Romania - RO
+
+ { 226, 1, "Vodafone", "Vodafone" },
+ { 226, 2, "Romtelecom", "Romtelecom" },
+ { 226, 3, "Cosmote", "Cosmote" },
+ { 226, 4, "Cosmote/Zapp", "Cosmote/Zapp" },
+ { 226, 5, "Digi.Mobil", "Digi.Mobil" },
+ { 226, 6, "Cosmote/Zapp", "Cosmote/Zapp" },
+ { 226, 10, "Orange", "Orange" },
+ { 226, 15, "Idilis", "Idilis" },
+
+ // Russian Federation - RU
+
+ { 250, 1, "MTS", "MTS" },
+ { 250, 2, "MegaFon", "MegaFon" },
+ { 250, 3, "NCC", "NCC" },
+ { 250, 4, "Sibchallenge", "Sibchallenge" },
+ { 250, 5, "ETK", "ETK" },
+ { 250, 6, "CJSC Saratov System of Cellular Communications", "CJSC Saratov System of Cellular Communications" },
+ { 250, 7, "SMARTS", "SMARTS" },
+ { 250, 9, "Skylink", "Skylink" },
+ { 250, 10, "DTC", "DTC" },
+ { 250, 11, "Yota", "Yota" },
+ { 250, 12, "Baykalwestcom", "Baykalwestcom" },
+ { 250, 12, "Akos", "Akos" },
+ { 250, 13, "KUGSM", "KUGSM" },
+ { 250, 14, "MegaFon", "MegaFon" },
+ { 250, 15, "SMARTS", "SMARTS" },
+ { 250, 16, "NTC", "NTC" },
+ { 250, 17, "Utel", "Utel" },
+ { 250, 18, "Osnova Telecom", "Osnova Telecom" },
+ { 250, 19, "INDIGO", "INDIGO" },
+ { 250, 20, "Tele2", "Tele2" },
+ { 250, 23, "Mobicom - Novosibirsk", "Mobicom - Novosibirsk" },
+ { 250, 28, "Beeline", "Beeline" },
+ { 250, 35, "MOTIV", "MOTIV" },
+ { 250, 38, "Tambov GSM", "Tambov GSM" },
+ { 250, 39, "Rostelecom", "Rostelecom" },
+ { 250, 44, "Stavtelesot / North Caucasian GSM", "Stavtelesot / North Caucasian GSM" },
+ { 250, 50, "MTS", "MTS" },
+ { 250, 91, "Sonic Duo", "Sonic Duo" },
+ { 250, 92, "Primtelefon", "Primtelefon" },
+ { 250, 93, "Telecom XXI", "Telecom XXI" },
+ { 250, 99, "Beeline", "Beeline" },
+
+ // Rwanda - RW
+
+ { 635, 10, "MTN", "MTN" },
+ { 635, 12, "Rwandatel", "Rwandatel" },
+ { 635, 13, "Tigo", "Tigo" },
+ { 635, 14, "Airtel", "Airtel" },
+ { 635, 17, "Olleh Rwanda Networks", "Olleh Rwanda Networks" },
+
+ // Saint Kitts and Nevis - KN
+
+ { 356, 50, "Digicel", "Digicel" },
+ { 356, 70, "Chippie", "Chippie" },
+ { 356, 110, "LIME", "LIME" },
+
+ // Saint Lucia - LC
+
+ { 358, 50, "Digicel", "Digicel" },
+ { 358, 110, "Cable & Wireless", "Cable & Wireless" },
+
+ // Saint Pierre and Miquelon (France) - PM
+
+ { 308, 1, "Ameris", "Ameris" },
+ { 308, 2, "GLOBALTEL", "GLOBALTEL" },
+
+ // Saint Vincent and the Grenadines - VC
+
+ { 360, 70, "Digicel", "Digicel" },
+ { 360, 100, "Cingular Wireless", "Cingular Wireless" },
+ { 360, 110, "Lime", "Lime" },
+
+ // Samoa - WS
+
+ { 549, 1, "Digicel", "Digicel" },
+ { 549, 27, "Bluesky", "Bluesky" },
+
+ // San Marino - SM
+
+ { 292, 1, "PRIMA", "PRIMA" },
+
+ // Sao Tome and Principe - ST
+
+ { 626, 1, "CSTmovel", "CSTmovel" },
+
+ // Saudi Arabia - SA
+
+ { 420, 1, "Al Jawal (STC )", "Al Jawal (STC )" },
+ { 420, 3, "Mobily", "Mobily" },
+ { 420, 4, "Zain SA", "Zain SA" },
+ { 420, 21, "RGSM", "RGSM" },
+
+ // Senegal - SN
+
+ { 608, 1, "Orange", "Orange" },
+ { 608, 2, "Tigo", "Tigo" },
+ { 608, 3, "Expresso", "Expresso" },
+ { 608, 4, "CSU-SA", "CSU-SA" },
+
+ // Serbia - RS
+
+ { 220, 1, "Telenor", "Telenor" },
+ { 220, 2, "Telenor", "Telenor" },
+ { 220, 3, "mt:s", "mt:s" },
+ { 220, 5, "VIP", "VIP" },
+
+ // Seychelles - SC
+
+ { 633, 1, "Cable & Wireless", "Cable & Wireless" },
+ { 633, 2, "Mediatech International", "Mediatech International" },
+ { 633, 10, "Airtel", "Airtel" },
+
+ // Sierra Leone - SL
+
+ { 619, 1, "Airtel", "Airtel" },
+ { 619, 3, "Africell", "Africell" },
+ { 619, 4, "Comium", "Comium" },
+ { 619, 5, "Africell", "Africell" },
+ { 619, 6, "SierraTel", "SierraTel" },
+ { 619, 25, "Mobitel", "Mobitel" },
+
+ // Singapore - SG
+
+ { 525, 1, "SingTel", "SingTel" },
+ { 525, 2, "SingTel-G18", "SingTel-G18" },
+ { 525, 3, "M1", "M1" },
+ { 525, 5, "StarHub", "StarHub" },
+ { 525, 6, "StarHub", "StarHub" },
+ { 525, 7, "SingTel", "SingTel" },
+ { 525, 12, "Grid", "Grid" },
+
+ // Slovakia - SK
+
+ { 231, 1, "Orange", "Orange" },
+ { 231, 2, "Telekom", "Telekom" },
+ { 231, 3, "Unient Communications", "Unient Communications" },
+ { 231, 4, "T-Mobile", "T-Mobile" },
+ { 231, 6, "O2", "O2" },
+ { 231, 99, "ŽSR", "ŽSR" },
+
+ // Slovenia - SI
+
+ { 293, 31, "Mobitel", "Mobitel" },
+ { 293, 40, "Si.mobil", "Si.mobil" },
+ { 293, 41, "Mobitel", "Mobitel" },
+ { 293, 51, "Mobitel", "Mobitel" },
+ { 293, 64, "T-2", "T-2" },
+ { 293, 70, "Tušmobil", "Tušmobil" },
+
+ // Solomon Islands - SB
+
+ { 540, 1, "BREEZE", "BREEZE" },
+ { 540, 2, "BeMobile", "BeMobile" },
+
+ // Somalia - SO
+
+ { 637, 1, "Telesom", "Telesom" },
+ { 637, 4, "SomaCyber", "SomaCyber" },
+ { 637, 4, "Somafone", "Somafone" },
+ { 637, 10, "Nationlink", "Nationlink" },
+ { 637, 50, "Hormuud", "Hormuud" },
+ { 637, 30, "Golis", "Golis" },
+ { 637, 57, "Unittel", "Unittel" },
+ { 637, 60, "Nationlink Telecom", "Nationlink Telecom" },
+ { 637, 71, "Somtel", "Somtel" },
+ { 637, 82, "Telcom", "Telcom" },
+
+ // South Africa - ZA
+
+ { 655, 1, "Vodacom", "Vodacom" },
+ { 655, 2, "Telkom Mobile / 8.ta / Telekom SA", "Telkom Mobile / 8.ta / Telekom SA" },
+ { 655, 6, "Sentech", "Sentech" },
+ { 655, 7, "Cell C", "Cell C" },
+ { 655, 10, "MTN", "MTN" },
+ { 655, 11, "South African Police Service Gauteng", "South African Police Service Gauteng" },
+ { 655, 13, "Neotel", "Neotel" },
+ { 655, 14, "Neotel", "Neotel" },
+ { 655, 19, "iBurst", "iBurst" },
+ { 655, 21, "Cape Town Metropolitan Council", "Cape Town Metropolitan Council" },
+ { 655, 30, "Bokamoso Consortium", "Bokamoso Consortium" },
+ { 655, 31, "Karabo Telecoms (Pty) Ltd.", "Karabo Telecoms (Pty) Ltd." },
+ { 655, 32, "Ilizwi Telecommunications", "Ilizwi Telecommunications" },
+ { 655, 33, "Thinta Thinta Telecommunications", "Thinta Thinta Telecommunications" },
+ { 655, 50, "Ericsson South Africa (Pty) Ltd", "Ericsson South Africa (Pty) Ltd" },
+ { 655, 51, "Integrat (Pty) Ltd", "Integrat (Pty) Ltd" },
+
+ // South Sudan - SS
+
+ { 659, 2, "MTN", "MTN" },
+ { 659, 3, "Gemtel", "Gemtel" },
+ { 659, 4, "Vivacell", "Vivacell" },
+ { 659, 6, "Zain", "Zain" },
+ { 659, 7, "Sudani", "Sudani" },
+
+ // Spain - ES
+
+ { 214, 1, "Vodafone", "Vodafone" },
+ { 214, 3, "Orange", "Orange" },
+ { 214, 4, "Yoigo", "Yoigo" },
+ { 214, 5, "TME", "TME" },
+ { 214, 6, "Vodafone", "Vodafone" },
+ { 214, 7, "movistar", "movistar" },
+ { 214, 8, "Euskaltel", "Euskaltel" },
+ { 214, 9, "Orange", "Orange" },
+ { 214, 15, "BT", "BT" },
+ { 214, 16, "TeleCable", "TeleCable" },
+ { 214, 17, "Móbil R", "Móbil R" },
+ { 214, 18, "ONO", "ONO" },
+ { 214, 19, "Simyo", "Simyo" },
+ { 214, 20, "Fonyou", "Fonyou" },
+ { 214, 21, "Jazztel", "Jazztel" },
+ { 214, 22, "DigiMobil", "DigiMobil" },
+ { 214, 23, "Barablu", "Barablu" },
+ { 214, 24, "Eroski", "Eroski" },
+ { 214, 25, "Lycamobile", "Lycamobile" },
+ { 214, 28, "Consorcio de Telecomunicaciones Avanzadas, S.A.", "Consorcio de Telecomunicaciones Avanzadas, S.A." },
+ { 214, 29, "NEO-SKY 2002, S.A.", "NEO-SKY 2002, S.A." },
+ { 214, 30, "Compatel Limited", "Compatel Limited" },
+ { 214, 31, "Red Digital De Telecomunicaciones de las Islas Baleares, S.L.", "Red Digital De Telecomunicaciones de las Islas Baleares, S.L." },
+ { 214, 32, "Tuenti", "Tuenti" },
+
+ // Sri Lanka - LK
+
+ { 413, 1, "Mobitel", "Mobitel" },
+ { 413, 2, "Dialog", "Dialog" },
+ { 413, 3, "Etisalat", "Etisalat" },
+ { 413, 5, "Airtel", "Airtel" },
+ { 413, 8, "Hutch", "Hutch" },
+
+ // Sudan - SD
+
+ { 634, 1, "Zain SD", "Zain SD" },
+ { 634, 2, "MTN", "MTN" },
+ { 634, 5, "Canar Telecom", "Canar Telecom" },
+ { 634, 7, "Sudani One", "Sudani One" },
+ { 634, 9, "Privet Network", "Privet Network" },
+
+ // Suriname - SR
+
+ { 746, 2, "Telesur", "Telesur" },
+ { 746, 3, "Digicel", "Digicel" },
+ { 746, 4, "Intelsur N.V. / UTS N.V.", "Intelsur N.V. / UTS N.V." },
+
+ // Swaziland - SZ
+
+ { 653, 10, "Swazi MTN", "Swazi MTN" },
+
+ // Sweden - SE
+
+ { 240, 1, "Telia", "Telia" },
+ { 240, 2, "3", "3" },
+ { 240, 3, "Net 1", "Net 1" },
+ { 240, 4, "SWEDEN", "SWEDEN" },
+ { 240, 5, "Sweden 3G", "Sweden 3G" },
+ { 240, 6, "Telenor", "Telenor" },
+ { 240, 7, "Tele2", "Tele2" },
+ { 240, 8, "Telenor", "Telenor" },
+ { 240, 9, "djuice", "djuice" },
+ { 240, 10, "Spring Mobil", "Spring Mobil" },
+ { 240, 11, "Lindholmen Science Park AB", "Lindholmen Science Park AB" },
+ { 240, 12, "Lycamobile", "Lycamobile" },
+ { 240, 13, "Alltele Företag Sverige AB", "Alltele Företag Sverige AB" },
+ { 240, 14, "TDC Sverige AB", "TDC Sverige AB" },
+ { 240, 15, "Wireless Maingate Nordic AB", "Wireless Maingate Nordic AB" },
+ { 240, 16, "42 Telecom AB", "42 Telecom AB" },
+ { 240, 17, "Götalandsnätet AB", "Götalandsnätet AB" },
+ { 240, 18, "Generic Mobile Systems Sweden AB", "Generic Mobile Systems Sweden AB" },
+ { 240, 19, "Vectone Mobile / Delight Mobile", "Vectone Mobile / Delight Mobile" },
+ { 240, 20, "Wireless Maingate Messaging Services AB", "Wireless Maingate Messaging Services AB" },
+ { 240, 21, "MobiSir", "MobiSir" },
+ { 240, 22, "EuTel AB", "EuTel AB" },
+ { 240, 23, "Infobip Limited", "Infobip Limited" },
+ { 240, 24, "Sweden 2G", "Sweden 2G" },
+ { 240, 25, "Digitel Mobile Srl", "Digitel Mobile Srl" },
+ { 240, 26, "Beepsend AB", "Beepsend AB" },
+ { 240, 27, "Fogg Mobile AB", "Fogg Mobile AB" },
+ { 240, 28, "CoolTEL Aps", "CoolTEL Aps" },
+ { 240, 29, "Mercury International Carrier Services", "Mercury International Carrier Services" },
+ { 240, 30, "NextGen Mobile Ltd.", "NextGen Mobile Ltd." },
+ { 240, 31, "Mobimax AB", "Mobimax AB" },
+ { 240, 32, "Compatel Limited", "Compatel Limited" },
+ { 240, 33, "Mobile Arts AB", "Mobile Arts AB" },
+ { 240, 34, "Pro Net Telecommunications Services Ltd.", "Pro Net Telecommunications Services Ltd." },
+ { 240, 35, "42 Telecom LTD", "42 Telecom LTD" },
+ { 240, 36, "interactive digital media GmbH", "interactive digital media GmbH" },
+ { 240, 37, "CLX Networks AB", "CLX Networks AB" },
+ { 240, 38, "Voxbone", "Voxbone" },
+ { 240, 39, "iCentrex Sweden AB", "iCentrex Sweden AB" },
+ { 240, 40, "ReWiCom Scandinavia AB", "ReWiCom Scandinavia AB" },
+ { 240, 41, "Shyam Telecom UK Ltd.", "Shyam Telecom UK Ltd." },
+ { 240, 42, "Telenor Connexion AB", "Telenor Connexion AB" },
+ { 240, 43, "MobiWeb Ltd.", "MobiWeb Ltd." },
+ { 240, 44, "Limitless Mobile AB", "Limitless Mobile AB" },
+
+ // Switzerland - CH
+
+ { 228, 1, "Swisscom", "Swisscom" },
+ { 228, 2, "Sunrise", "Sunrise" },
+ { 228, 3, "Orange", "Orange" },
+ { 228, 5, "Togewanet AG (Comfone)", "Togewanet AG (Comfone)" },
+ { 228, 6, "SBB-CFF-FFS", "SBB-CFF-FFS" },
+ { 228, 7, "IN&Phone", "IN&Phone" },
+ { 228, 8, "Tele4u", "Tele4u" },
+ { 228, 9, "Comfone", "Comfone" },
+ { 228, 12, "Sunrise", "Sunrise" },
+ { 228, 50, "3G Mobile AG", "3G Mobile AG" },
+ { 228, 51, "BebbiCell AG", "BebbiCell AG" },
+ { 228, 52, "Barablu", "Barablu" },
+ { 228, 53, "UPC", "UPC" },
+ { 228, 54, "Lyca Mobile", "Lyca Mobile" },
+ { 228, 99, "Swisscom", "Swisscom" },
+
+ // Syria - SY
+
+ { 417, 1, "Syriatel", "Syriatel" },
+ { 417, 2, "MTN", "MTN" },
+
+ // Taiwan - TW
+
+ { 466, 1, "FarEasTone", "FarEasTone" },
+ { 466, 5, "APTG", "APTG" },
+ { 466, 6, "FarEasTone", "FarEasTone" },
+ { 466, 11, "Chunghwa LDM", "Chunghwa LDM" },
+ { 466, 88, "FarEasTone", "FarEasTone" },
+ { 466, 89, "VIBO", "VIBO" },
+ { 466, 92, "Chungwa", "Chungwa" },
+ { 466, 93, "MobiTai", "MobiTai" },
+ { 466, 97, "Taiwan Mobile", "Taiwan Mobile" },
+ { 466, 99, "TransAsia", "TransAsia" },
+
+ // Tajikistan - TJ
+
+ { 436, 1, "Tcell", "Tcell" },
+ { 436, 2, "Tcell", "Tcell" },
+ { 436, 3, "Megafon Tajikistan", "Megafon Tajikistan" },
+ { 436, 4, "Babilon-M", "Babilon-M" },
+ { 436, 5, "Beeline", "Beeline" },
+ { 436, 12, "Tcell", "Tcell" },
+
+ // Tanzania - TZ
+
+ { 640, 2, "tiGO", "tiGO" },
+ { 640, 3, "Zantel", "Zantel" },
+ { 640, 4, "Vodacom", "Vodacom" },
+ { 640, 5, "Airtel", "Airtel" },
+ { 640, 6, "Dovetel Limited", "Dovetel Limited" },
+ { 640, 7, "Tanzania Telecommunication Company LTD (TTCL)", "Tanzania Telecommunication Company LTD (TTCL)" },
+ { 640, 8, "Benson Informatics Limited", "Benson Informatics Limited" },
+ { 640, 9, "ExcellentCom Tanzania Limited", "ExcellentCom Tanzania Limited" },
+ { 640, 11, "SmileCom", "SmileCom" },
+
+ // Thailand - TH
+
+ { 520, 1, "AIS", "AIS" },
+ { 520, 2, "CAT CDMA", "CAT CDMA" },
+ { 520, 3, "AIS 3G", "AIS 3G" },
+ { 520, 4, "truemove H 4G LTE", "truemove H 4G LTE" },
+ { 520, 5, "dtac TriNet", "dtac TriNet" },
+ { 520, 10, "?", "?" },
+ { 520, 15, "TOT 3G", "TOT 3G" },
+ { 520, 18, "dtac", "dtac" },
+ { 520, 23, "AIS GSM 1800", "AIS GSM 1800" },
+ { 520, 25, "WE PCT", "WE PCT" },
+ { 520, 47, "Telephone Organization of Thailand (TOT)", "Telephone Organization of Thailand (TOT)" },
+ { 520, 99, "truemove", "truemove" },
+
+ // Togo - TG
+
+ { 615, 1, "Togo Cell", "Togo Cell" },
+ { 615, 3, "Moov", "Moov" },
+
+ // Tonga - TO
+
+ { 539, 1, "U-Call", "U-Call" },
+ { 539, 43, "Shoreline Communication", "Shoreline Communication" },
+ { 539, 88, "Digicel", "Digicel" },
+
+ // Trinidad and Tobago - TT
+
+ { 374, 12, "bmobile", "bmobile" },
+ { 374, 130, "Digicel", "Digicel" },
+
+ // Tunisia - TN
+
+ { 605, 1, "Orange", "Orange" },
+ { 605, 2, "Tunicell", "Tunicell" },
+ { 605, 3, "Tunisiana", "Tunisiana" },
+
+ // Turkey - TR
+
+ { 286, 1, "Turkcell", "Turkcell" },
+ { 286, 2, "Vodafone", "Vodafone" },
+ { 286, 3, "Avea", "Avea" },
+ { 286, 4, "Aycell", "Aycell" },
+
+ // Turkmenistan - TM
+
+ { 438, 1, "MTS (BARASH Communication)", "MTS (BARASH Communication)" },
+ { 438, 2, "TM-Cell", "TM-Cell" },
+
+ // Turks and Caicos Islands - TC
+
+ { 338, 50, "Digicel", "Digicel" },
+ { 376, 350, "C&W", "C&W" },
+ { 376, 352, "Islandcom", "Islandcom" },
+
+ // Tuvalu - TV
+
+ { 553, 1, "TTC", "TTC" },
+
+ // Uganda - UG
+
+ { 641, 1, "Airtel", "Airtel" },
+ { 641, 10, "MTN", "MTN" },
+ { 641, 11, "UTL ( Telecom Limited)", "UTL ( Telecom Limited)" },
+ { 641, 14, "Orange", "Orange" },
+ { 641, 22, "Warid Telecom", "Warid Telecom" },
+ { 641, 33, "Smile", "Smile" },
+ { 641, 44, "K2", "K2" },
+ { 641, 66, "i-Tel", "i-Tel" },
+
+ // Ukraine - UA
+
+ { 255, 1, "MTS", "MTS" },
+ { 255, 2, "Beeline", "Beeline" },
+ { 255, 3, "Kyivstar", "Kyivstar" },
+ { 255, 4, "IT", "IT" },
+ { 255, 5, "Golden Telecom", "Golden Telecom" },
+ { 255, 6, "life:)", "life:)" },
+ { 255, 7, "3Mob", "3Mob" },
+ { 255, 21, "PEOPLEnet", "PEOPLEnet" },
+ { 255, 23, "CDMA Ukraine", "CDMA Ukraine" },
+ { 255, 25, "NEWTONE", "NEWTONE" },
+
+ // United Arab Emirates - AE
+
+ { 424, 2, "Etisalat", "Etisalat" },
+ { 424, 3, "du", "du" },
+
+ // United Kingdom - GB
+
+ { 234, 1, "Vectone Mobile", "Vectone Mobile" },
+ { 234, 2, "O2 (UK)", "O2 (UK)" },
+ { 234, 3, "Airtel-Vodafone", "Airtel-Vodafone" },
+ { 234, 4, "FMS Solutions Ltd", "FMS Solutions Ltd" },
+ { 234, 5, "COLT Mobile Telecommunications Limited", "COLT Mobile Telecommunications Limited" },
+ { 234, 6, "Internet Computer Bureau Limited", "Internet Computer Bureau Limited" },
+ { 234, 7, "Cable & Wireless Worldwide", "Cable & Wireless Worldwide" },
+ { 234, 8, "OnePhone (UK) Ltd", "OnePhone (UK) Ltd" },
+ { 234, 9, "Tismi BV", "Tismi BV" },
+ { 234, 10, "O2 (UK)", "O2 (UK)" },
+ { 234, 11, "O2 (UK)", "O2 (UK)" },
+ { 234, 12, "Railtrack", "Railtrack" },
+ { 234, 13, "Railtrack", "Railtrack" },
+ { 234, 14, "Hay Systems Ltd", "Hay Systems Ltd" },
+ { 234, 15, "Vodafone UK", "Vodafone UK" },
+ { 234, 16, "Talk Talk", "Talk Talk" },
+ { 234, 17, "FleXtel Limited", "FleXtel Limited" },
+ { 234, 18, "Cloud9", "Cloud9" },
+ { 234, 19, "Private Mobile Networks PMN", "Private Mobile Networks PMN" },
+ { 234, 20, "3", "3" },
+ { 234, 22, "RoutoMessaging", "RoutoMessaging" },
+ { 234, 23, "Icron Network Limited", "Icron Network Limited" },
+ { 234, 24, "Greenfone", "Greenfone" },
+ { 234, 25, "Truphone", "Truphone" },
+ { 234, 26, "Lycamobile", "Lycamobile" },
+ { 234, 27, "Teleena UK Limited", "Teleena UK Limited" },
+ { 234, 28, "Marathon Telecom Ltd", "Marathon Telecom Ltd" },
+ { 234, 29, "aql", "aql" },
+ { 234, 30, "T-Mobile UK", "T-Mobile UK" },
+ { 234, 31, "Virgin Mobile UK", "Virgin Mobile UK" },
+ { 234, 32, "Virgin Mobile UK", "Virgin Mobile UK" },
+ { 234, 33, "Orange (UK)", "Orange (UK)" },
+ { 234, 34, "Orange (UK)", "Orange (UK)" },
+ { 234, 35, "JSC Ingenium (UK) Limited", "JSC Ingenium (UK) Limited" },
+ { 234, 36, "Sure (Isle of Man) Limited", "Sure (Isle of Man) Limited" },
+ { 234, 37, "Synectiv Ltd", "Synectiv Ltd" },
+ { 234, 38, "Virgin Mobile UK", "Virgin Mobile UK" },
+ { 234, 39, "SSE Energy Supply Limited", "SSE Energy Supply Limited" },
+ { 234, 50, "JT", "JT" },
+ { 234, 51, "UK Broadband", "UK Broadband" },
+ { 234, 52, "Shyam Telecom UK Ltd", "Shyam Telecom UK Ltd" },
+ { 234, 53, "Limitless Mobile Ltd", "Limitless Mobile Ltd" },
+ { 234, 55, "Cable & Wireless Guernsey / Sure Mobile (Jersey)", "Cable & Wireless Guernsey / Sure Mobile (Jersey)" },
+ { 234, 58, "Manx Telecom", "Manx Telecom" },
+ { 234, 76, "BT", "BT" },
+ { 234, 78, "Airwave", "Airwave" },
+ { 234, 86, "EE", "EE" },
+ { 235, 1, "EE", "EE" },
+ { 235, 2, "EE", "EE" },
+ { 235, 3, "UK Broadband", "UK Broadband" },
+ { 235, 77, "BT", "BT" },
+ { 235, 91, "Vodafone United Kingdom", "Vodafone United Kingdom" },
+ { 235, 92, "Cable & Wireless UK", "Cable & Wireless UK" },
+ { 235, 94, "Hutchison 3G UK Ltd", "Hutchison 3G UK Ltd" },
+ { 235, 95, "Network Rail Infrastructure Limited", "Network Rail Infrastructure Limited" },
+
+ // United States of America - US
+
+ { 310, 4, "Verizon", "Verizon" },
+ { 310, 5, "Verizon", "Verizon" },
+ { 310, 10, "MCI", "MCI" },
+ { 310, 13, "MobileTel", "MobileTel" },
+ { 310, 14, "Testing", "Testing" },
+ { 310, 16, "Cricket Communications", "Cricket Communications" },
+ { 310, 17, "North Sight Communications Inc.", "North Sight Communications Inc." },
+ { 310, 20, "Union Telephone Company", "Union Telephone Company" },
+ { 310, 26, "T-Mobile", "T-Mobile" },
+ { 310, 30, "AT&T", "AT&T" },
+ { 310, 34, "Airpeak", "Airpeak" },
+ { 310, 40, "Concho", "Concho" },
+ { 310, 46, "SIMMETRY", "SIMMETRY" },
+ { 310, 53, "Virgin Mobile US", "Virgin Mobile US" },
+ { 310, 54, "Alltel US", "Alltel US" },
+ { 310, 60, "Consolidated Telcom", "Consolidated Telcom" },
+ { 310, 66, "U.S. Cellular", "U.S. Cellular" },
+ { 310, 70, "Highland Cellular", "Highland Cellular" },
+ { 310, 80, "Corr", "Corr" },
+ { 310, 90, "Cricket Communications", "Cricket Communications" },
+ { 310, 100, "Plateau Wireless", "Plateau Wireless" },
+ { 310, 110, "PTI Pacifica", "PTI Pacifica" },
+ { 310, 120, "Sprint", "Sprint" },
+ { 310, 150, "AT&T", "AT&T" },
+ { 310, 160, "T-Mobile", "T-Mobile" },
+ { 310, 170, "AT&T", "AT&T" },
+ { 310, 180, "West Central", "West Central" },
+ { 310, 190, "Dutch Harbor", "Dutch Harbor" },
+ { 310, 200, "T-Mobile", "T-Mobile" },
+ { 310, 210, "T-Mobile", "T-Mobile" },
+ { 310, 220, "T-Mobile", "T-Mobile" },
+ { 310, 230, "T-Mobile", "T-Mobile" },
+ { 310, 240, "T-Mobile", "T-Mobile" },
+ { 310, 250, "T-Mobile", "T-Mobile" },
+ { 310, 260, "T-Mobile", "T-Mobile" },
+ { 310, 270, "T-Mobile", "T-Mobile" },
+ { 310, 280, "AT&T", "AT&T" },
+ { 310, 290, "T-Mobile", "T-Mobile" },
+ { 310, 300, "Big Sky Mobile", "Big Sky Mobile" },
+ { 310, 310, "T-Mobile", "T-Mobile" },
+ { 310, 311, "Farmers Wireless", "Farmers Wireless" },
+ { 310, 320, "Cellular One", "Cellular One" },
+ { 310, 330, "T-Mobile", "T-Mobile" },
+ { 310, 340, "Westlink", "Westlink" },
+ { 310, 350, "Carolina Phone", "Carolina Phone" },
+ { 310, 380, "AT&T", "AT&T" },
+ { 310, 390, "Cellular One of East Texas", "Cellular One of East Texas" },
+ { 310, 400, "i CAN_GSM", "i CAN_GSM" },
+ { 310, 410, "AT&T", "AT&T" },
+ { 310, 420, "Cincinnati Bell", "Cincinnati Bell" },
+ { 310, 430, "Alaska Digitel", "Alaska Digitel" },
+ { 310, 440, "Cellular One", "Cellular One" },
+ { 310, 450, "Viaero", "Viaero" },
+ { 310, 460, "Simmetry", "Simmetry" },
+ { 310, 470, "nTelos", "nTelos" },
+ { 310, 480, "Choice Phone", "Choice Phone" },
+ { 310, 490, "T-Mobile", "T-Mobile" },
+ { 310, 500, "Alltel", "Alltel" },
+ { 310, 510, "Airtel", "Airtel" },
+ { 310, 520, "VeriSign", "VeriSign" },
+ { 310, 530, "West Virginia Wireless", "West Virginia Wireless" },
+ { 310, 540, "Oklahoma Western", "Oklahoma Western" },
+ { 310, 560, "AT&T", "AT&T" },
+ { 310, 570, "Cellular One", "Cellular One" },
+ { 310, 580, "T-Mobile", "T-Mobile" },
+ { 310, 590, "Alltel", "Alltel" },
+ { 310, 610, "Epic Touch", "Epic Touch" },
+ { 310, 620, "Coleman County Telecom", "Coleman County Telecom" },
+ { 310, 630, "AmeriLink PCS", "AmeriLink PCS" },
+ { 310, 640, "Airadigm", "Airadigm" },
+ { 310, 650, "Jasper", "Jasper" },
+ { 310, 660, "T-Mobile", "T-Mobile" },
+ { 310, 670, "Northstar", "Northstar" },
+ { 310, 680, "AT&T", "AT&T" },
+ { 310, 690, "Immix", "Immix" },
+ { 310, 730, "SeaMobile", "SeaMobile" },
+ { 310, 740, "Convey", "Convey" },
+ { 310, 750, "Appalachian Wireless", "Appalachian Wireless" },
+ { 310, 760, "Panhandle", "Panhandle" },
+ { 310, 770, "i wireless", "i wireless" },
+ { 310, 780, "Airlink PCS", "Airlink PCS" },
+ { 310, 790, "PinPoint", "PinPoint" },
+ { 310, 800, "T-Mobile", "T-Mobile" },
+ { 310, 830, "Caprock", "Caprock" },
+ { 310, 840, "telna Mobile", "telna Mobile" },
+ { 310, 850, "Aeris", "Aeris" },
+ { 310, 870, "PACE", "PACE" },
+ { 310, 880, "Advantage", "Advantage" },
+ { 310, 890, "Unicel", "Unicel" },
+ { 310, 900, "Mid-Rivers Wireless", "Mid-Rivers Wireless" },
+ { 310, 910, "First Cellular", "First Cellular" },
+ { 310, 940, "Iris Wireless LLC", "Iris Wireless LLC" },
+ { 310, 950, "XIT Wireless", "XIT Wireless" },
+ { 310, 960, "Plateau Wireless", "Plateau Wireless" },
+ { 310, 970, "Globalstar", "Globalstar" },
+ { 310, 980, "AT&T", "AT&T" },
+ { 310, 990, "AT&T", "AT&T" },
+ { 311, 10, "Chariton Valley", "Chariton Valley" },
+ { 311, 12, "Verizon", "Verizon" },
+ { 311, 20, "Missouri RSA 5 Partnership", "Missouri RSA 5 Partnership" },
+ { 311, 30, "Indigo Wireless", "Indigo Wireless" },
+ { 311, 40, "Commnet Wireless", "Commnet Wireless" },
+ { 311, 50, "Wikes Cellular", "Wikes Cellular" },
+ { 311, 60, "Farmers Cellular", "Farmers Cellular" },
+ { 311, 70, "Easterbrooke", "Easterbrooke" },
+ { 311, 80, "Pine Cellular", "Pine Cellular" },
+ { 311, 90, "Long Lines Wireless", "Long Lines Wireless" },
+ { 311, 100, "High Plains Wireless", "High Plains Wireless" },
+ { 311, 110, "High Plains Wireless", "High Plains Wireless" },
+ { 311, 120, "Choice Phone", "Choice Phone" },
+ { 311, 130, "Cell One Amarillo", "Cell One Amarillo" },
+ { 311, 140, "Sprocket", "Sprocket" },
+ { 311, 150, "Wilkes Cellular", "Wilkes Cellular" },
+ { 311, 160, "Endless Mountains Wireless", "Endless Mountains Wireless" },
+ { 311, 170, "PetroCom", "PetroCom" },
+ { 311, 180, "Cingular Wireless", "Cingular Wireless" },
+ { 311, 190, "Cellular Properties", "Cellular Properties" },
+ { 311, 210, "Emery Telcom Wireless", "Emery Telcom Wireless" },
+ { 311, 220, "U.S. Cellular", "U.S. Cellular" },
+ { 311, 230, "C Spire Wireless", "C Spire Wireless" },
+ { 311, 330, "Bug Tussel Wireless", "Bug Tussel Wireless" },
+ { 311, 480, "Verizon", "Verizon" },
+ { 311, 481, "Verizon", "Verizon" },
+ { 311, 490, "Sprint Corporation", "Sprint Corporation" },
+ { 311, 580, "U.S. Cellular", "U.S. Cellular" },
+ { 311, 660, "metroPCS", "metroPCS" },
+ { 311, 870, "Boost", "Boost" },
+ { 311, 960, "Lycamobile", "Lycamobile" },
+ { 311, 970, "Big River Broadband", "Big River Broadband" },
+ { 312, 590, "NMU", "NMU" },
+ { 313, 100, "700&nbsp;MHz Public Safety Broadband", "700&nbsp;MHz Public Safety Broadband" },
+ { 313, 101, "700&nbsp;MHz Public Safety Broadband", "700&nbsp;MHz Public Safety Broadband" },
+ { 316, 10, "Nextel", "Nextel" },
+ { 316, 11, "Southern Communications Services", "Southern Communications Services" },
+
+ // Uruguay - UY
+
+ { 748, 1, "Antel", "Antel" },
+ { 748, 7, "Movistar", "Movistar" },
+ { 748, 10, "Claro", "Claro" },
+
+ // Uzbekistan - UZ
+
+ { 434, 1, "Buztel", "Buztel" },
+ { 434, 2, "Uzmacom", "Uzmacom" },
+ { 434, 4, "Beeline", "Beeline" },
+ { 434, 5, "Ucell", "Ucell" },
+ { 434, 6, "Perfectum Mobile", "Perfectum Mobile" },
+ { 434, 7, "MTS", "MTS" },
+ { 434, 3, "UzMobile", "UzMobile" },
+
+ // Vanuatu - VU
+
+ { 541, 1, "SMILE", "SMILE" },
+ { 541, 5, "Digicel", "Digicel" },
+ { 541, 7, "WanTok", "WanTok" },
+
+ // Vatican - VA
+
+
+ // Venezuela - VE
+
+ { 734, 1, "Digitel", "Digitel" },
+ { 734, 2, "Digitel GSM", "Digitel GSM" },
+ { 734, 3, "Digitel", "Digitel" },
+ { 734, 4, "movistar", "movistar" },
+ { 734, 6, "Movilnet", "Movilnet" },
+
+ // Vietnam - VN
+
+ { 452, 1, "MobiFone", "MobiFone" },
+ { 452, 2, "Vinaphone", "Vinaphone" },
+ { 452, 3, "S-Fone", "S-Fone" },
+ { 452, 4, "Viettel Mobile", "Viettel Mobile" },
+ { 452, 5, "Vietnamobile (HT Mobile )", "Vietnamobile (HT Mobile )" },
+ { 452, 6, "EVNTelecom", "EVNTelecom" },
+ { 452, 7, "G-Mobile", "G-Mobile" },
+ { 452, 8, "3G EVNTelecom", "3G EVNTelecom" },
+
+ // Yemen - YE
+
+ { 421, 1, "SabaFon", "SabaFon" },
+ { 421, 2, "MTN", "MTN" },
+ { 421, 3, "Yemen Mobile", "Yemen Mobile" },
+ { 421, 4, "HiTS-UNITEL", "HiTS-UNITEL" },
+
+ // Zambia - ZM
+
+ { 645, 1, "Airtel", "Airtel" },
+ { 645, 2, "MTN", "MTN" },
+ { 645, 3, "ZAMTEL", "ZAMTEL" },
+
+ // Zimbabwe - ZW
+
+ { 648, 1, "Net*One", "Net*One" },
+ { 648, 3, "Telecel", "Telecel" },
+ { 648, 4, "Econet", "Econet" },
+ { 901, 1, "ICO", "ICO" },
+ { 901, 2, "''Unassigned''", "''Unassigned''" },
+ { 901, 3, "Iridium", "Iridium" },
+ { 901, 4, "''Unassigned''", "''Unassigned''" },
+ { 901, 5, "Thuraya RMSS Network", "Thuraya RMSS Network" },
+ { 901, 6, "Thuraya Satellite Telecommunications Company", "Thuraya Satellite Telecommunications Company" },
+ { 901, 7, "''Unassigned''", "''Unassigned''" },
+ { 901, 8, "''Unassigned''", "''Unassigned''" },
+ { 901, 9, "''Unassigned''", "''Unassigned''" },
+ { 901, 10, "ACeS", "ACeS" },
+ { 901, 11, "Inmarsat", "Inmarsat" },
+ { 901, 12, "Telenor", "Telenor" },
+ { 901, 13, "GSM.AQ", "GSM.AQ" },
+ { 901, 14, "AeroMobile AS", "AeroMobile AS" },
+ { 901, 15, "OnAir", "OnAir" },
+ { 901, 16, "Jasper Systems", "Jasper Systems" },
+ { 901, 17, "Navitas", "Navitas" },
+ { 901, 18, "Cellular @Sea", "Cellular @Sea" },
+ { 901, 19, "Vodafone Malta Maritime", "Vodafone Malta Maritime" },
+ { 901, 20, "Intermatica", "Intermatica" },
+ { 901, 21, "''Unassigned''", "''Unassigned''" },
+ { 901, 22, "MediaLincc Ltd", "MediaLincc Ltd" },
+ { 901, 23, "''Unassigned''", "''Unassigned''" },
+ { 901, 24, "iNum", "iNum" },
+ { 901, 25, "''Unassigned''", "''Unassigned''" },
+ { 901, 26, "TIM", "TIM" },
+ { 901, 27, "OnAir", "OnAir" },
+ { 901, 28, "Vodafone", "Vodafone" },
+ { 901, 29, "Telenor", "Telenor" },
+ { 901, 30, "''Unassigned''", "''Unassigned''" },
+ { 901, 31, "Orange", "Orange" },
+ { 901, 32, "Sky High", "Sky High" },
+ { 901, 33, "Smart Communications", "Smart Communications" },
+ { 901, 34, "tyntec GmbH", "tyntec GmbH" },
+ { 901, 35, "Globecomm Network Services", "Globecomm Network Services" },
+ { 901, 36, "Azerfon", "Azerfon" },
+ { 901, 39, "MTX Connect Ltd", "MTX Connect Ltd" },
+ { 901, 88, "UN Office for the Coordination of Humanitarian Affairs (OCHA)", "UN Office for the Coordination of Humanitarian Affairs (OCHA)" },
+};
+
+unsigned int plmn_list_count = sizeof(plmn_list) /
+ sizeof(struct plmn_list_entry);
+
+#endif
diff --git a/include/plmn_list.sh b/include/plmn_list.sh
new file mode 100755
index 0000000..0a17068
--- /dev/null
+++ b/include/plmn_list.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+#
+# Copyright 2012-2014 Paul Kocialkowski, GPLv3+
+#
+# This script is a dirty hack, keep in mind that is was written in a hurry
+# and doesn't reflect our code cleanness standards.
+# Any (working) replacement written in a cleaner way, such as a perl script
+# would be greatly appreciated.
+
+echo "/*"
+echo " * This list was generated from:"
+echo " * http://en.wikipedia.org/wiki/Mobile_country_code"
+echo " *"
+echo " * Date: "$( date "+%x %X" )
+echo " * Copyright: Wikipedia Contributors, Creative Commons"
+echo " * Attribution-ShareAlike License"
+echo " */"
+echo ""
+echo "#ifndef _PLMN_LIST_H_"
+echo "#define _PLMN_LIST_H_"
+echo ""
+echo "#include <stdlib.h>"
+echo ""
+echo "struct plmn_list_entry {"
+echo " unsigned int mcc;"
+echo " unsigned int mnc;"
+echo " char *operator_long;"
+echo " char *operator_short;"
+echo "};"
+echo ""
+echo "struct plmn_list_entry plmn_list[] = {"
+
+wget "http://en.wikipedia.org/w/index.php?title=Special:Export&pages=Mobile_country_code&action=submit" --quiet -O - | tr -d '\n' | sed -e "s|.*<text[^>]*>\(.*\)</text>.*|\1|g" -e "s/|-/\n|-\n/g" | sed -e "s/\(}===.*\)/\n\1/g" -e "s/===={.*/===={\n/g" -e "s/\&amp;/\&/g" -e "s/\&lt;[^\&]*\&gt;//g" -e "s/&quot;//g" -e "s#\[http[^]]*\]##g" -e "s#\[\[\([^]|]*\)|\([^]]*\)\]\]#\2#g" -e "s#\[\[\([^]]*\)\]\]#\1#g" -e "s#\[\([^] ]*\) \([^]]*\)\]#\2#g" -e "s#{{[^}]*}}##g" | tail -n +2 | sed "s|.*==== *\([^=]*\) *====.*|// \1|g" | grep -v "|-" | while read line
+do
+ if [ "$line" = "" ]
+ then
+ continue
+ fi
+
+ test=$( echo "$line" | grep -P "^//" )
+
+ if [ ! "$test" = "" ]
+ then
+ echo "\n\t$line\n" | sed -e "s#[^|]*|\(.*\)#// \1#g" -e "s/^ //g" -e "s/ $//g" -e "s/ / /g"
+ continue
+ fi
+
+ test=$( echo "$line" | grep "||" )
+
+ if [ "$test" = "" ]
+ then
+ continue
+ fi
+
+ mcc=$( echo "$line" | sed -e "s#[^|]*|[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\).*#\1#g" -e "s/^[ |\t]*//g" -e "s/ [ |\t]*$//g" -e "s/[^1-9]*\([0-9]*\).*/\1/g")
+ mnc=$( echo "$line" | sed -e "s#[^|]*|[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\).*#\2#g" -e "s/^[ |\t]*//g" -e "s/ [ |\t]*$//g" -e "s/[^1-9]*\([0-9]*\).*/\1/g")
+ brand=$( echo "$line" | sed -e "s#[^|]*|[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\).*#\3#g" -e "s/^[ |\t]*//g" -e "s/ [ |\t]*$//g" )
+ operator=$( echo "$line" | sed -e "s#[^|]*|[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\).*#\4#g" -e "s/^[ |\t]*//g" -e "s/ [ |\t]*$//g" )
+
+ if [ "$mcc" = "" ] || [ "$mcc" = "?" ]
+ then
+ continue
+ fi
+
+ if [ "$mnc" = "" ] || [ "$mnc" = "?" ]
+ then
+ continue
+ fi
+
+ if [ "$brand" = "" ]
+ then
+ if [ "$operator" = "" ]
+ then
+ continue
+ fi
+
+ echo "\t{ $mcc, $mnc, \"$operator\", \"$operator\" },"
+ else
+ echo "\t{ $mcc, $mnc, \"$brand\", \"$brand\" },"
+ fi
+done
+
+echo "};"
+echo ""
+echo "unsigned int plmn_list_count = sizeof(plmn_list) /"
+echo "\tsizeof(struct plmn_list_entry);"
+echo ""
+echo "#endif"
diff --git a/include/sim.h b/include/sim.h
new file mode 100644
index 0000000..2adbfff
--- /dev/null
+++ b/include/sim.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of QMI-RIL.
+ *
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
+ * 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/>.
+ */
+
+#ifndef _SIM_H_
+#define _SIM_H_
+
+#define SIM_COMMAND_READ_BINARY 0xB0
+#define SIM_COMMAND_UPDATE_BINARY 0xD6
+#define SIM_COMMAND_READ_RECORD 0xB2
+#define SIM_COMMAND_UPDATE_RECORD 0xDC
+#define SIM_COMMAND_SEEK 0xA2
+#define SIM_COMMAND_GET_RESPONSE 0xC0
+
+#define SIM_FILE_STRUCTURE_TRANSPARENT 0x00
+#define SIM_FILE_STRUCTURE_LINEAR_FIXED 0x01
+
+#define SIM_FILE_TYPE_MF 0x01
+#define SIM_FILE_TYPE_DF 0x02
+#define SIM_FILE_TYPE_EF 0x04
+
+struct sim_file_response {
+ unsigned char rfu12[2];
+ unsigned short file_size;
+ unsigned short file_id;
+ unsigned char file_type;
+ unsigned char rfu3;
+ unsigned char access_condition[3];
+ unsigned char file_status;
+ unsigned char file_length;
+ unsigned char file_structure;
+ unsigned char record_length;
+} __attribute__((__packed__));
+
+#endif
diff --git a/misc.c b/misc.c
new file mode 100644
index 0000000..9eda760
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,289 @@
+/*
+ * 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 <qmi-ril.h>
+
+static void
+get_software_version_ready(QmiClientDms *client, GAsyncResult *res,
+ RIL_Token token)
+{
+ const gchar *version;
+ QmiMessageDmsGetSoftwareVersionOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_dms_get_software_version_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_dms_get_software_version_output_get_result (output, &error)) {
+ RIL_LOGE("error: couldn't get software version: %s",
+ error->message);
+ goto error;
+ }
+
+ qmi_message_dms_get_software_version_output_get_version(
+ output, &version, NULL);
+
+ RIL_LOGD("Software version: %s", version);
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) version, sizeof(version));
+
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_dms_get_software_version_output_unref(output);
+}
+
+int ril_request_baseband_version(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ request = ril_request_find_request_status(RIL_REQUEST_BASEBAND_VERSION,
+ RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ qmi_client_dms_get_software_version(ctx->DmsClient, NULL, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_software_version_ready,
+ token);
+
+ return RIL_REQUEST_HANDLED;
+}
+
+static void uim_get_imsi_ready(QmiClientDms *client, GAsyncResult *res,
+ RIL_Token token)
+{
+ const gchar *str = NULL;
+ QmiMessageDmsUimGetImsiOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_dms_uim_get_imsi_finish (client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_dms_uim_get_imsi_output_get_result (output, &error)) {
+ RIL_LOGE("error: couldn't get IMSI: %s", error->message);
+ goto error;
+ }
+
+ qmi_message_dms_uim_get_imsi_output_get_imsi(output, &str, NULL);
+
+ RIL_LOGD("UIM IMSI retrieved: '%s'", str);
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) str, sizeof(str));
+
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_dms_uim_get_imsi_output_unref(output);
+}
+
+int ril_request_get_imsi(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ request = ril_request_find_request_status(RIL_REQUEST_GET_IMSI, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ qmi_client_dms_uim_get_imsi(ctx->DmsClient, NULL, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)uim_get_imsi_ready,
+ token);
+
+ return RIL_REQUEST_HANDLED;
+}
+
+static void get_ids_ready(QmiClientDms *client, GAsyncResult *res,
+ RIL_Token token)
+{
+ struct ril_request *request;
+ const gchar *imei_buf;
+ char *imei = NULL;
+ char *imeisv = NULL;
+ unsigned int imeisvlen;
+ QmiMessageDmsGetIdsOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_dms_get_ids_finish (client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_dms_get_ids_output_get_result(output, &error)) {
+ RIL_LOGE("error: couldn't get IDs: %s", error->message);
+ goto error;
+ }
+
+ qmi_message_dms_get_ids_output_get_imei(output, &imei_buf, NULL);
+
+ imei = (char*) imei_buf;
+
+ // not yet a way to retrieve the IMEISV, so set 00 as SVN
+ imeisvlen = strlen(imei) - 1 + 3;
+ imeisv = (char*) malloc(imeisvlen);
+ strcpy(imeisv, imei);
+ imeisv = strcat(imeisv, "00");
+ imeisv[imeisvlen] = '\0';
+
+ RIL_LOGD("Device IDs retrieved:\n"
+ "\tIMEI: '%s'\n"
+ "\tIMEISV: '%s'", imei, imeisv);
+
+ request = ril_request_find_request_status(RIL_REQUEST_GET_IMEI, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ ril_request_complete(request->token, RIL_E_SUCCESS, (void *) imei, sizeof(imei));
+
+ request = ril_request_find_request_status(RIL_REQUEST_GET_IMEISV, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ ril_request_complete(request->token, RIL_E_SUCCESS, (void *) imeisv, sizeof(imeisv));
+
+ goto complete;
+
+error:
+ request = ril_request_find_request_status(RIL_REQUEST_GET_IMEI, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ ril_request_complete(request->token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ request = ril_request_find_request_status(RIL_REQUEST_GET_IMEISV, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ ril_request_complete(request->token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ free(imei);
+ free(imeisv);
+
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_dms_get_ids_output_unref(output);
+}
+
+int ril_request_get_imei(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ request = ril_request_find_request_status(RIL_REQUEST_GET_IMEI, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ // The response to the IMEISV request will hold IMEI as well
+ request = ril_request_find_request_status(RIL_REQUEST_GET_IMEISV, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_HANDLED;
+
+ qmi_client_dms_get_ids(ctx->DmsClient, NULL, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_ids_ready,
+ token);
+
+ return RIL_REQUEST_HANDLED;
+}
+
+int ril_request_get_imeisv(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ request = ril_request_find_request_status(RIL_REQUEST_GET_IMEISV, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ // The response to the IMEI request will hold IMEISV as well
+ request = ril_request_find_request_status(RIL_REQUEST_GET_IMEI, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_HANDLED;
+
+ qmi_client_dms_get_ids(ctx->DmsClient, NULL, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_ids_ready,
+ token);
+
+ return RIL_REQUEST_HANDLED;
+}
+
+int ril_request_screen_state(void *data, size_t size, RIL_Token token)
+{
+ int value;
+ int rc;
+
+ if (data == NULL || size < sizeof(int)) {
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return RIL_REQUEST_COMPLETED;
+ }
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ value = *((int *) data);
+
+ if (value)
+ ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0);
+
+ ril_request_complete(token, RIL_E_SUCCESS, NULL, 0);
+
+ return RIL_REQUEST_COMPLETED;
+}
diff --git a/network.c b/network.c
new file mode 100644
index 0000000..e0488c0
--- /dev/null
+++ b/network.c
@@ -0,0 +1,664 @@
+/*
+ * 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>
+#include <ctype.h>
+
+#define LOG_TAG "RIL"
+#include <utils/Log.h>
+
+#include <qmi-ril.h>
+#include <plmn_list.h>
+
+void serving_system_indication_cb(QmiClientNas *client,
+ QmiIndicationNasServingSystemOutput *output)
+{
+ RIL_LOGD("Got serving system indication");
+ ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
+ NULL, 0);
+}
+
+int qmi2ril_signal_strength(gint8 qmi_strength)
+{
+ int ril_strength;
+
+ ril_strength = (int) qmi_strength / 2 + 56;
+
+ if (ril_strength < 0)
+ ril_strength = 0;
+ else if (ril_strength > 31)
+ ril_strength = 31;
+
+ return ril_strength;
+}
+
+void nas_event_report_indication_cb(QmiClientNas *client,
+ QmiIndicationNasEventReportOutput *output)
+{
+ RIL_SignalStrength_v6 ril_strength;
+ gint8 qmi_strength, rsrq;
+ gint16 rsrp, snr;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return;
+
+ qmi_indication_nas_event_report_output_get_signal_strength(
+ output, &qmi_strength, NULL, NULL);
+
+ RIL_LOGD("Successfully got signal strength through indication\n"
+ "Current: '%d dBm'", qmi_strength);
+
+ /* RSRQ */
+ if (qmi_indication_nas_event_report_output_get_rsrq(
+ output, &rsrq, NULL, NULL)) {
+ RIL_LOGD("RSRQ: '%d dB'", rsrq);
+ } else
+ return;
+
+ /* LTE SNR */
+ if (qmi_indication_nas_event_report_output_get_lte_snr(
+ output, &snr, NULL)) {
+ RIL_LOGD("SNR: '%.1lf dB'", (0.1) * ((gdouble)snr));
+ } else
+ return;
+
+ /* LTE RSRP */
+ if (qmi_indication_nas_event_report_output_get_lte_rsrp(
+ output, &rsrp, NULL)) {
+ RIL_LOGD("RSRP: '%d dBm'", rsrp);
+ } else
+ return;
+
+ memset(&ril_strength, -1, sizeof(RIL_SignalStrength_v6));
+ ril_strength.LTE_SignalStrength.signalStrength = qmi2ril_signal_strength(qmi_strength);
+ ril_strength.LTE_SignalStrength.rsrp = -rsrp;
+ ril_strength.LTE_SignalStrength.rsrq = -rsrq;
+ ril_strength.LTE_SignalStrength.rssnr = snr;
+ ril_strength.LTE_SignalStrength.cqi = INT_MAX;
+
+ ril_request_unsolicited(RIL_UNSOL_SIGNAL_STRENGTH,
+ (void *) &ril_strength,
+ sizeof(ril_strength));
+
+ RIL_LOGD("reported signal strength");
+}
+
+static void get_signal_strength_ready(QmiClientNas *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ RIL_SignalStrength_v6 ril_strength;
+ QmiMessageNasGetSignalStrengthOutput *output;
+ GError *error = NULL;
+ gint8 qmi_strength, rsrq;
+ gint16 rsrp, snr;
+ int rc;
+
+ output = qmi_client_nas_get_signal_strength_finish(client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_nas_get_signal_strength_output_get_result(output, &error)) {
+ RIL_LOGE("%s: error: couldn't get signal strength: %s",
+ __func__, error->message);
+ goto error;
+ }
+
+ qmi_message_nas_get_signal_strength_output_get_signal_strength(
+ output, &qmi_strength, NULL, NULL);
+
+ RIL_LOGD("Successfully got signal strength\n"
+ "Current: '%d dBm'", qmi_strength);
+
+ /* RSRQ */
+ if (qmi_message_nas_get_signal_strength_output_get_rsrq(
+ output, &rsrq, NULL, NULL)) {
+ RIL_LOGD("RSRQ: '%d dB'", rsrq);
+ } else
+ goto error;
+
+ /* LTE SNR */
+ if (qmi_message_nas_get_signal_strength_output_get_lte_snr(
+ output, &snr, NULL)) {
+ RIL_LOGD("SNR: '%.1lf dB'", (0.1) * ((gdouble)snr));
+ } else
+ goto error;
+
+ /* LTE RSRP */
+ if (qmi_message_nas_get_signal_strength_output_get_lte_rsrp(
+ output, &rsrp, NULL)) {
+ RIL_LOGD("RSRP: '%d dBm'", rsrp);
+ } else
+ goto error;
+
+ memset(&ril_strength, -1, sizeof(RIL_SignalStrength_v6));
+ ril_strength.LTE_SignalStrength.signalStrength = qmi2ril_signal_strength(qmi_strength);
+ ril_strength.LTE_SignalStrength.rsrp = -rsrp;
+ ril_strength.LTE_SignalStrength.rsrq = -rsrq;
+ ril_strength.LTE_SignalStrength.rssnr = snr;
+ ril_strength.LTE_SignalStrength.cqi = INT_MAX;
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &ril_strength, sizeof(ril_strength));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_nas_get_signal_strength_output_unref(output);
+}
+
+static QmiMessageNasGetSignalStrengthInput
+*ril2qmi_signal_strength_input_create(void)
+{
+ GError *error = NULL;
+ QmiMessageNasGetSignalStrengthInput *input;
+ QmiNasSignalStrengthRequest mask;
+
+ mask = (QMI_NAS_SIGNAL_STRENGTH_REQUEST_RSRQ |
+ QMI_NAS_SIGNAL_STRENGTH_REQUEST_LTE_SNR |
+ QMI_NAS_SIGNAL_STRENGTH_REQUEST_LTE_RSRP);
+
+ input = qmi_message_nas_get_signal_strength_input_new();
+ if (!qmi_message_nas_get_signal_strength_input_set_request_mask(
+ input,
+ mask,
+ &error)) {
+ RIL_LOGE("error: couldn't create input data bundle: '%s'",
+ error->message);
+ g_error_free(error);
+ qmi_message_nas_get_signal_strength_input_unref(input);
+ input = NULL;
+ }
+
+ return input;
+}
+
+int ril_request_signal_strength(void *data, size_t size, RIL_Token token)
+{
+ QmiMessageNasGetSignalStrengthInput *input;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ input = ril2qmi_signal_strength_input_create();
+
+ qmi_client_nas_get_signal_strength(ctx->NasClient, input, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_signal_strength_ready,
+ token);
+
+ qmi_message_nas_get_signal_strength_input_unref(input);
+
+ return RIL_REQUEST_HANDLED;
+}
+
+static void
+get_system_selection_preference_ready(QmiClientNas *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageNasGetSystemSelectionPreferenceOutput *output;
+ GError *error = NULL;
+ QmiNasNetworkSelectionPreference qmi_network_selection;
+ int ril_network_selection;
+
+ output = qmi_client_nas_get_system_selection_preference_finish(
+ client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_nas_get_system_selection_preference_output_get_result(output, &error)) {
+ RIL_LOGE("error: couldn't get system_selection preference: %s", error->message);
+ goto error;
+ }
+
+ RIL_LOGD("Successfully got system selection preference");
+
+ if (qmi_message_nas_get_system_selection_preference_output_get_network_selection_preference(
+ output, &qmi_network_selection, NULL)) {
+ RIL_LOGD("Network selection preference: '%s'",
+ qmi_nas_network_selection_preference_get_string(qmi_network_selection));
+
+ switch (qmi_network_selection) {
+ case QMI_NAS_NETWORK_SELECTION_PREFERENCE_AUTOMATIC:
+ ril_network_selection = 0;
+ case QMI_NAS_NETWORK_SELECTION_PREFERENCE_MANUAL:
+ ril_network_selection = 1;
+ }
+ } else
+ goto error;
+
+ ril_request_complete(token, RIL_E_SUCCESS,
+ (void *) &ril_network_selection,
+ sizeof(ril_network_selection));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_nas_get_system_selection_preference_output_unref(output);
+}
+
+int ril_request_query_network_selection_mode(void *data, size_t size,
+ RIL_Token token)
+{
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ qmi_client_nas_get_system_selection_preference(ctx->NasClient,
+ NULL, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_system_selection_preference_ready,
+ token);
+
+ return RIL_REQUEST_HANDLED;
+}
+
+int ril_request_set_preferred_network_type(void *data, size_t size,
+ RIL_Token token)
+{
+ int type;
+ int rc;
+
+ if (data == NULL || size < sizeof(int))
+ goto error;
+
+ type = *((int *) data);
+
+ RIL_LOGD("request for setting %d as preferred network type", type);
+ RIL_LOGE("%s: TODO: implement me!", __func__);
+
+ ril_request_complete(token, RIL_E_SUCCESS, NULL, 0);
+ rc = RIL_REQUEST_COMPLETED;
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ rc = RIL_REQUEST_COMPLETED;
+
+complete:
+ return rc;
+}
+
+int qmi2ril_net_operator(QmiMessageNasGetOperatorNameOutputOperatorPlmnListElement *element,
+ char **operator_long, char **operator_short,
+ char **plmn)
+{
+ char buffer[7] = { 0 };
+ unsigned int mcc = 0;
+ unsigned int mnc = 0;
+ unsigned int i;
+ int rc;
+
+ *plmn = NULL;
+
+ strncpy(buffer, element->mcc, 3);
+ strncpy(&buffer[3], element->mnc, 3);
+ for (i = 0; i < 7; i++) {
+ if (!isdigit(buffer[i])) {
+ buffer[i] = '\0';
+ break;
+ }
+ }
+
+ if (buffer[0] == '\0')
+ goto error;
+
+ *plmn = strdup(buffer);
+
+ *operator_long = NULL;
+ *operator_short = NULL;
+
+ if (buffer[5] == '\0')
+ rc = sscanf((char *) &buffer, "%3u%2u", &mcc, &mnc);
+ else
+ rc = sscanf((char *) &buffer, "%3u%3u", &mcc, &mnc);
+ if (rc < 2)
+ goto error;
+
+ for (i = 0 ; i < plmn_list_count ; i++) {
+ if (plmn_list[i].mcc == mcc
+ && plmn_list[i].mnc == mnc) {
+ *operator_long = strdup(plmn_list[i].operator_long);
+ *operator_short = strdup(plmn_list[i].operator_short);
+ }
+ }
+
+ if (*operator_long == NULL || *operator_short == NULL) {
+ RIL_LOGE("%s: Finding operator with PLMN %d%d failed", __func__, mcc, mnc);
+ goto error;
+ } else
+ RIL_LOGD("%s: Found operator with PLMN %d%d", __func__,
+ mcc, mnc);
+
+ rc = 0;
+ goto complete;
+
+error:
+ if (*plmn != NULL) {
+ free(*plmn);
+ *plmn = NULL;
+ }
+
+ if (operator_long != NULL && *operator_long != NULL) {
+ free(*operator_long);
+ *operator_long = NULL;
+ }
+
+ if (operator_short != NULL && *operator_short != NULL) {
+ free(*operator_short);
+ *operator_short = NULL;
+ }
+
+ rc = -1;
+
+complete:
+ return rc;
+}
+
+static void get_operator_name_ready(QmiClientNas *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageNasGetOperatorNameOutput *output;
+ QmiMessageNasGetOperatorNameOutputOperatorPlmnListElement *element;
+ GError *error = NULL;
+ GArray *array;
+ char *operator[3] = { NULL };
+
+ output = qmi_client_nas_get_operator_name_finish(client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_nas_get_operator_name_output_get_result(output, &error)) {
+ RIL_LOGE("error: couldn't get operator name data: %s", error->message);
+ goto error;
+ }
+
+ RIL_LOGD("Successfully got operator name data");
+
+ if (qmi_message_nas_get_operator_name_output_get_operator_plmn_list(
+ output, &array, NULL)) {
+ element = &g_array_index(array, QmiMessageNasGetOperatorNameOutputOperatorPlmnListElement, 0);
+ if(qmi2ril_net_operator(element, &operator[0],
+ &operator[1], &operator[2]))
+ goto error;
+
+ RIL_LOGD("MCC/MNC: '%s', name '%s' '%s'",
+ operator[2], operator[0], operator[1]);
+ }
+
+error:
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &operator, sizeof(operator));
+
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_nas_get_operator_name_output_unref(output);
+}
+
+int ril_request_operator(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ request = ril_request_find_request_status(RIL_REQUEST_OPERATOR, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ RIL_LOGD("requesting operator name");
+ qmi_client_nas_get_operator_name(ctx->NasClient, NULL, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_operator_name_ready,
+ token);
+
+ return RIL_REQUEST_HANDLED;
+}
+
+static void get_serving_system_ready(QmiClientNas *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageNasGetServingSystemOutput *output;
+ QmiNasRegistrationState registration_state;
+ QmiNasRoamingIndicatorStatus roaming;
+ QmiNasCallBarringStatus cs_call_barring, ps_call_barring;
+ GArray *data_service_capability;
+ QmiNasDataCapability data_cap;
+ guint16 lac;
+ guint32 cid;
+ unsigned char ril_status_voice = 10;
+ unsigned char ril_status_data;
+ RIL_RadioTechnology ril_technology;
+ char **voice_registration[15] = { NULL };
+ char *data_registration[5] = { NULL };
+ char **registration;
+ size_t registration_size;
+ struct ril_request *request;
+ GError *error = NULL;
+
+ output = qmi_client_nas_get_serving_system_finish(client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_nas_get_serving_system_output_get_result(output, &error)) {
+ RIL_LOGE("error: couldn't get serving system: %s", error->message);
+ goto error;
+ }
+
+ RIL_LOGD("Successfully got serving system");
+
+ qmi_message_nas_get_serving_system_output_get_serving_system(
+ output, &registration_state, NULL, NULL, NULL, NULL, NULL);
+
+ qmi_message_nas_get_serving_system_output_get_data_service_capability(
+ output, &data_service_capability, NULL);
+
+ qmi_message_nas_get_serving_system_output_get_roaming_indicator(
+ output, &roaming, NULL);
+ qmi_message_nas_get_serving_system_output_get_lac_3gpp(
+ output, &lac, NULL);
+ qmi_message_nas_get_serving_system_output_get_cid_3gpp(
+ output, &cid, NULL);
+
+ if(qmi_message_nas_get_serving_system_output_get_call_barring_status(
+ output, &cs_call_barring, &ps_call_barring,
+ NULL)) {
+ if ((cs_call_barring == QMI_NAS_CALL_BARRING_STATUS_NORMAL_ONLY
+ || cs_call_barring == QMI_NAS_CALL_BARRING_STATUS_NO_CALLS)
+ && (ps_call_barring == QMI_NAS_CALL_BARRING_STATUS_NORMAL_ONLY
+ || ps_call_barring == QMI_NAS_CALL_BARRING_STATUS_NO_CALLS))
+ ril_status_voice = 0;
+ }
+
+ switch (registration_state) {
+ case QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED:
+ ril_status_voice += 0;
+ break;
+ case QMI_NAS_REGISTRATION_STATE_REGISTERED:
+ switch (roaming) {
+ case QMI_NAS_ROAMING_INDICATOR_STATUS_ON:
+ ril_status_voice = 5;
+ break;
+ case QMI_NAS_ROAMING_INDICATOR_STATUS_OFF:
+ ril_status_voice = 1;
+ break;
+ }
+ break;
+ case QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING:
+ ril_status_voice += 2;
+ break;
+ case QMI_NAS_REGISTRATION_STATE_REGISTRATION_DENIED:
+ ril_status_voice += 3;
+ break;
+ case QMI_NAS_REGISTRATION_STATE_UNKNOWN:
+ default:
+ ril_status_voice += 4;
+ }
+
+ // status for DATA_REGISTRATION_STATE doesn't include
+ // emergency status and is only 0 <= ril_status_data <= 5
+ if (ril_status_voice > 5)
+ ril_status_data = ril_status_voice - 10;
+ else
+ ril_status_data = ril_status_voice;
+
+ if (data_service_capability->len > 0)
+ data_cap = g_array_index(data_service_capability,
+ QmiNasDataCapability, 0);
+ else
+ data_cap = QMI_NAS_DATA_CAPABILITY_NONE;
+
+ switch (data_cap) {
+ case QMI_NAS_DATA_CAPABILITY_GPRS:
+ ril_technology = RADIO_TECH_GPRS;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_EDGE:
+ ril_technology = RADIO_TECH_EDGE;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_HSDPA:
+ ril_technology = RADIO_TECH_HSDPA;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_HSUPA:
+ ril_technology = RADIO_TECH_HSUPA;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_WCDMA:
+ ril_technology = RADIO_TECH_UMTS;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_EVDO_REV_0:
+ ril_technology = RADIO_TECH_EVDO_0;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_EVDO_REV_A:
+ ril_technology = RADIO_TECH_EVDO_A;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_GSM:
+ ril_technology = RADIO_TECH_GSM;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_EVDO_REV_B:
+ ril_technology = RADIO_TECH_EVDO_B;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_LTE:
+ ril_technology = RADIO_TECH_LTE;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_HSDPA_PLUS:
+ case QMI_NAS_DATA_CAPABILITY_DC_HSDPA_PLUS:
+ ril_technology = RADIO_TECH_HSPAP;
+ break;
+ case QMI_NAS_DATA_CAPABILITY_NONE:
+ default:
+ ril_technology = RADIO_TECH_UNKNOWN;
+ }
+
+ request = ril_request_find_token(token);
+
+ if (request != NULL
+ && request->request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
+ registration = (char **) &voice_registration;
+ registration_size = sizeof(voice_registration);
+ asprintf(&registration[0], "%d", ril_status_voice);
+ asprintf(&registration[1], "%x", lac);
+ asprintf(&registration[2], "%x", cid);
+ asprintf(&registration[3], "%d", ril_technology);
+ } else if (request != NULL
+ && request->request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
+ registration = (char **) &data_registration;
+ registration_size = sizeof(data_registration);
+ asprintf(&registration[0], "%d", ril_status_data);
+ asprintf(&registration[1], "%x", lac);
+ asprintf(&registration[2], "%x", cid);
+ asprintf(&registration[3], "%d", ril_technology);
+ /*
+ * number of simultanious data connections
+ * TODO: make it possible to setup more using multiple
+ * devices
+ */
+ asprintf(&registration[4], "%d", 1);
+ } else
+ goto error;
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) registration, registration_size);
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_nas_get_serving_system_output_unref(output);
+}
+
+int ril_request_registration_state(void *data, size_t size,
+ RIL_Token token)
+{
+ struct ril_request *request;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ request = ril_request_find_request_status(RIL_REQUEST_VOICE_REGISTRATION_STATE, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ request = ril_request_find_request_status(RIL_REQUEST_DATA_REGISTRATION_STATE, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ qmi_client_nas_get_serving_system(ctx->NasClient, NULL, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_serving_system_ready,
+ token);
+
+ return RIL_REQUEST_HANDLED;
+}
diff --git a/power.c b/power.c
new file mode 100644
index 0000000..dde9e17
--- /dev/null
+++ b/power.c
@@ -0,0 +1,147 @@
+/*
+ * 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 <qmi-ril.h>
+
+void dms_event_report_indication_cb(QmiClientDms *client,
+ QmiIndicationDmsEventReportOutput *output)
+{
+ QmiDmsOperatingMode mode;
+
+ qmi_indication_dms_event_report_output_get_operating_mode(
+ output, &mode, NULL);
+
+ RIL_LOGD("Got operating mode indication:\n"
+ "\tMode: '%s'", qmi_dms_operating_mode_get_string(mode));
+
+ switch (mode) {
+ case QMI_DMS_OPERATING_MODE_LOW_POWER:
+ RIL_LOGD("Power state is low power mode");
+ ril_radio_state_update(RADIO_STATE_OFF);
+ break;
+ case QMI_DMS_OPERATING_MODE_SHUTTING_DOWN:
+ RIL_LOGD("Power: device is in the process of shutting down");
+ ril_radio_state_update(RADIO_STATE_OFF);
+ break;
+ case QMI_DMS_OPERATING_MODE_ONLINE:
+ RIL_LOGD("Power state is normal");
+ ril_radio_state_update(RADIO_STATE_SIM_NOT_READY);
+ break;
+ default:
+ RIL_LOGE("Unknown power state");
+ }
+}
+
+static void
+set_operating_mode_ready(QmiClientDms *client, GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageDmsSetOperatingModeOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_dms_set_operating_mode_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_dms_set_operating_mode_output_get_result(
+ output, &error)) {
+ RIL_LOGE("error: couldn't set operating mode: %s",
+ error->message);
+ goto error;
+ }
+
+ RIL_LOGD("Operating mode set successfully");
+
+ ril_request_complete(token, RIL_E_SUCCESS, NULL, 0);
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_dms_set_operating_mode_output_unref(output);
+}
+
+int ril_request_radio_power(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ int power_state;
+ QmiMessageDmsSetOperatingModeInput *input = NULL;
+ QmiDmsOperatingMode mode;
+ GError *error = NULL;
+ int rc;
+
+ if (data == NULL || size < sizeof(power_state))
+ goto error;
+
+ request = ril_request_find_request_status(RIL_REQUEST_RADIO_POWER, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ power_state = *((int *)data);
+
+ if (power_state > 0) {
+ RIL_LOGD("Requesting normal power state");
+ mode = QMI_DMS_OPERATING_MODE_ONLINE;
+ } else {
+ RIL_LOGD("Requesting low power mode power state");
+ mode = QMI_DMS_OPERATING_MODE_LOW_POWER;
+ }
+
+ input = qmi_message_dms_set_operating_mode_input_new();
+ if (!qmi_message_dms_set_operating_mode_input_set_mode(
+ input, mode, &error)) {
+ RIL_LOGE("error: couldn't create input data bundle: '%s'",
+ error->message);
+ goto error;
+ }
+
+ qmi_client_dms_set_operating_mode(ctx->DmsClient, input, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)set_operating_mode_ready,
+ token);
+
+ rc = RIL_REQUEST_HANDLED;
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ rc = RIL_REQUEST_COMPLETED;
+
+complete:
+ if (error)
+ g_error_free(error);
+ if (input)
+ qmi_message_dms_set_operating_mode_input_unref(input);
+
+ return rc;
+}
diff --git a/qmi-client.c b/qmi-client.c
new file mode 100644
index 0000000..ab47325
--- /dev/null
+++ b/qmi-client.c
@@ -0,0 +1,347 @@
+/*
+ * 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 <telephony/ril.h>
+
+#include <gio/gio.h>
+
+#include <qmi-ril.h>
+
+#define CDC_PATH "/dev/cdc-wdm2"
+
+static GCancellable *cancellable;
+static GFile *file;
+static QmiDevice *device;
+
+QmiService qmi_services[] = {
+ QMI_SERVICE_DMS,
+ QMI_SERVICE_NAS,
+ QMI_SERVICE_UIM,
+ QMI_SERVICE_WDS,
+ QMI_SERVICE_WDA,
+};
+
+unsigned int qmi_service_count = sizeof(qmi_services)
+ / sizeof(QmiService);
+unsigned int qmi_indications_count = 3;
+
+static unsigned int qmi_client_count = 0;
+static unsigned int qmi_client_failures = 0;
+static unsigned int qmi_indications_ready = 0;
+
+static void all_indications_ready()
+{
+ if (qmi_indications_ready < qmi_indications_count) {
+ RIL_LOGD("%d indications ready", qmi_indications_ready);
+ return;
+ } else {
+ RIL_LOGD("registered indications");
+ // initialization finished, main loop can now process
+ // requests
+ ril_radio_state_update(RADIO_STATE_OFF);
+ }
+}
+
+static void nas_set_event_report_ready(QmiClientNas *client,
+ GAsyncResult *res)
+{
+ QmiMessageNasSetEventReportOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_nas_set_event_report_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_nas_set_event_report_output_get_result(output, &error)) {
+ RIL_LOGE("Couldn't set nas event report: %s", error->message);
+ g_error_free(error);
+ qmi_message_nas_set_event_report_output_unref(output);
+
+ return;
+ }
+
+ qmi_message_nas_set_event_report_output_unref(output);
+
+ ctx->nas_event_report_indication_id =
+ g_signal_connect(ctx->NasClient, "event-report",
+ G_CALLBACK(nas_event_report_indication_cb),
+ NULL);
+
+ qmi_indications_ready++;
+ all_indications_ready();
+}
+
+static void nas_register_indications_ready(QmiClientNas *client,
+ GAsyncResult *res)
+{
+ QmiMessageNasRegisterIndicationsOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_nas_register_indications_finish(client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ g_error_free(error);
+ return;
+ }
+
+ if (!qmi_message_nas_register_indications_output_get_result(output, &error)) {
+ RIL_LOGE("Couldn't register nas indications: %s", error->message);
+ g_error_free(error);
+ qmi_message_nas_register_indications_output_unref(output);
+
+ return;
+ }
+
+ qmi_message_nas_register_indications_output_unref(output);
+
+ ctx->serving_system_indication_id =
+ g_signal_connect(ctx->NasClient, "serving-system",
+ G_CALLBACK(serving_system_indication_cb),
+ NULL);
+
+ qmi_indications_ready++;
+ all_indications_ready();
+}
+
+static void dms_set_event_report_ready(QmiClientDms *client,
+ GAsyncResult *res)
+{
+ QmiMessageDmsSetEventReportOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_dms_set_event_report_finish(client, res, &error);
+
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ g_error_free(error);
+ return;
+ }
+
+ if (!qmi_message_dms_set_event_report_output_get_result(output, &error)) {
+ RIL_LOGE("Couldn't set dms event report: %s", error->message);
+ g_error_free(error);
+ qmi_message_dms_set_event_report_output_unref(output);
+ return;
+ }
+
+ qmi_message_dms_set_event_report_output_unref(output);
+
+ ctx->dms_event_report_indication_id = g_signal_connect(
+ ctx->DmsClient,
+ "event-report",
+ G_CALLBACK(dms_event_report_indication_cb),
+ NULL);
+
+ qmi_indications_ready++;
+ all_indications_ready();
+}
+
+static void setup_indications()
+{
+ QmiMessageDmsSetEventReportInput *dms_event_report_input;
+ QmiMessageNasRegisterIndicationsInput *nas_register_input;
+ QmiMessageNasSetEventReportInput *nas_event_report_input;
+ static const gint8 thresholds_data[] = {-80, -40, 0, 40, 80};
+ GArray *thresholds;
+
+ dms_event_report_input = qmi_message_dms_set_event_report_input_new();
+ qmi_message_dms_set_event_report_input_set_operating_mode_reporting(
+ dms_event_report_input, TRUE, NULL);
+ qmi_client_dms_set_event_report(ctx->DmsClient,
+ dms_event_report_input, 5, NULL,
+ (GAsyncReadyCallback)dms_set_event_report_ready,
+ NULL);
+ qmi_message_dms_set_event_report_input_unref(dms_event_report_input);
+
+ nas_register_input = qmi_message_nas_register_indications_input_new();
+ qmi_message_nas_register_indications_input_set_serving_system_events(
+ nas_register_input, TRUE, NULL);
+ qmi_client_nas_register_indications(ctx->NasClient,
+ nas_register_input, 5, NULL,
+ (GAsyncReadyCallback)nas_register_indications_ready,
+ NULL);
+ qmi_message_nas_register_indications_input_unref(nas_register_input);
+
+ nas_event_report_input = qmi_message_nas_set_event_report_input_new();
+ thresholds = g_array_sized_new(FALSE, FALSE, sizeof (gint8),
+ G_N_ELEMENTS(thresholds_data));
+ g_array_append_vals(thresholds, thresholds_data,
+ G_N_ELEMENTS(thresholds_data));
+ qmi_message_nas_set_event_report_input_set_signal_strength_indicator(
+ nas_event_report_input, TRUE, thresholds, NULL);
+ g_array_unref(thresholds);
+ qmi_client_nas_set_event_report(ctx->NasClient,
+ nas_event_report_input, 5, NULL,
+ (GAsyncReadyCallback)nas_set_event_report_ready,
+ NULL);
+ qmi_message_nas_set_event_report_input_unref(nas_event_report_input);
+}
+
+static void allocate_client_ready(QmiDevice *dev, GAsyncResult *res)
+{
+ QmiClient *client;
+ QmiService service;
+ GError *error = NULL;
+
+ client = qmi_device_allocate_client_finish(dev, res, &error);
+ if (!client) {
+ RIL_LOGE("%s: error: couldn't create client: %s", __func__,
+ error->message);
+ qmi_client_failures++;
+ RIL_LOGE("increased failure counter to %d", qmi_client_failures);
+ return;
+ }
+
+ service = qmi_client_get_service(client);
+
+ switch (service) {
+ case QMI_SERVICE_DMS:
+ ctx->DmsClient = g_object_ref(QMI_CLIENT_DMS(client));
+ break;
+ case QMI_SERVICE_NAS:
+ ctx->NasClient = g_object_ref(QMI_CLIENT_NAS(client));
+ break;
+ case QMI_SERVICE_UIM:
+ ctx->UimClient = g_object_ref(QMI_CLIENT_UIM(client));
+ break;
+ case QMI_SERVICE_WDS:
+ ctx->WdsClient = g_object_ref(QMI_CLIENT_WDS(client));
+ break;
+ case QMI_SERVICE_WDA:
+ ctx->WdaClient = g_object_ref(QMI_CLIENT_WDA(client));
+ // configure it right away
+ qmi_set_raw_ip_mode();
+ break;
+ default:
+ RIL_LOGE("unknown service");
+ return;
+ }
+
+ RIL_LOGD("QMI client for service %s allocated",
+ qmi_service_get_string(service));
+ RIL_LOGD("%d of %d clients allocated", qmi_client_count,
+ qmi_service_count);
+
+ qmi_client_count++;
+
+ if (qmi_client_failures)
+ RIL_LOGD("%d failures", qmi_client_failures);
+
+ if (qmi_client_count == qmi_service_count)
+ setup_indications();
+}
+
+static void device_allocate_client(QmiDevice *dev)
+{
+ guint8 cid = QMI_CID_NONE;
+ unsigned int i;
+
+ ctx = g_slice_new(Context);
+ ctx->file = g_object_ref(file);
+ ctx->device = g_object_ref(device);
+ if (cancellable)
+ ctx->cancellable = g_object_ref(cancellable);
+
+ for (i = 0; i < qmi_service_count; i++)
+ qmi_device_allocate_client(dev, qmi_services[i], cid,
+ 10, cancellable,
+ (GAsyncReadyCallback)allocate_client_ready,
+ NULL);
+
+ RIL_LOGD("Started allocating QMI clients");
+}
+
+static void device_open_ready(QmiDevice *dev, GAsyncResult *res)
+{
+ GError *error = NULL;
+
+ if (!qmi_device_open_finish(dev, res, &error)) {
+ RIL_LOGE("error: couldn't open the QmiDevice: %s",
+ error->message);
+ qmi_client_failures++;
+ return;
+ }
+
+ RIL_LOGD("QMI Device at '%s' ready",
+ qmi_device_get_path_display(dev));
+
+ device_allocate_client(dev);
+}
+
+static void device_new_ready(GObject *unused, GAsyncResult *res)
+{
+ QmiDeviceOpenFlags open_flags = QMI_DEVICE_OPEN_FLAGS_NONE;
+ GError *error = NULL;
+
+ device = qmi_device_new_finish(res, &error);
+ if (!device) {
+ RIL_LOGE("error: couldn't create QmiDevice: %s",
+ error->message);
+ qmi_client_failures++;
+ return;
+ }
+
+ open_flags |= QMI_DEVICE_OPEN_FLAGS_AUTO;
+
+ /* Open the device */
+ qmi_device_open(device, open_flags, 15, cancellable,
+ (GAsyncReadyCallback)device_open_ready, NULL);
+}
+
+int create_qmi_clients(void)
+{
+ cancellable = g_cancellable_new();
+
+ file = g_file_new_for_path(CDC_PATH);
+
+ if(g_file_query_exists(file, NULL))
+ qmi_device_new(file, cancellable,
+ (GAsyncReadyCallback)device_new_ready,
+ NULL);
+ else {
+ RIL_LOGE("error opening file path");
+ return -1;
+ }
+
+ RIL_LOGD("started creating QMI clients");
+
+ return 0;
+}
+
+int all_clients_running(void)
+{
+ if (qmi_client_failures) {
+ return -1;
+ } else if (qmi_client_count < qmi_service_count
+ || qmi_indications_ready < qmi_indications_count
+ || ril_data->data_connection.raw_ip_mode == FALSE)
+ return 0;
+ else
+ return 1;
+}
diff --git a/qmi-ril.c b/qmi-ril.c
new file mode 100644
index 0000000..eb22b88
--- /dev/null
+++ b/qmi-ril.c
@@ -0,0 +1,1161 @@
+/*
+ * This file is part of QMI-RIL.
+ *
+ * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com>
+ * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr>
+ * 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>
+#include <ctype.h>
+
+#define LOG_TAG "RIL"
+#include <utils/Log.h>
+#include <telephony/ril.h>
+
+#include <glib-unix.h>
+
+#include <qmi-ril.h>
+
+static GMainLoop *loop;
+
+/*
+ * RIL data
+ */
+
+struct ril_data *ril_data = NULL;
+
+/*
+ * RIL request
+ */
+
+struct ril_request_handler ril_request_handlers[] = {
+ /* Power */
+ {
+ .request = RIL_REQUEST_RADIO_POWER,
+ .handler = ril_request_radio_power,
+ },
+ /* Call */
+ {
+ .request = RIL_REQUEST_GET_CURRENT_CALLS,
+ .handler = ril_request_get_current_calls,
+ },
+ /* SIM */
+ {
+ .request = RIL_REQUEST_GET_SIM_STATUS,
+ .handler = ril_request_get_sim_status,
+ },
+ {
+ .request = RIL_REQUEST_QUERY_FACILITY_LOCK,
+ .handler = ril_request_query_facility_lock,
+ },
+ {
+ .request = RIL_REQUEST_SIM_IO,
+ .handler = ril_request_sim_io,
+ },
+ /* Network */
+ {
+ .request = RIL_REQUEST_SIGNAL_STRENGTH,
+ .handler = ril_request_signal_strength,
+ },
+ {
+ .request = RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE,
+ .handler = ril_request_query_network_selection_mode,
+ },
+ {
+ .request = RIL_REQUEST_OPERATOR,
+ .handler = ril_request_operator,
+ },
+ {
+ .request = RIL_REQUEST_VOICE_REGISTRATION_STATE,
+ .handler = ril_request_registration_state,
+ },
+ {
+ .request = RIL_REQUEST_DATA_REGISTRATION_STATE,
+ .handler = ril_request_registration_state,
+ },
+ {
+ .request = RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
+ .handler = ril_request_set_preferred_network_type,
+ },
+ /* Misc */
+ {
+ .request = RIL_REQUEST_BASEBAND_VERSION,
+ .handler = ril_request_baseband_version,
+ },
+ {
+ .request = RIL_REQUEST_GET_IMSI,
+ .handler = ril_request_get_imsi,
+ },
+ {
+ .request = RIL_REQUEST_GET_IMEI,
+ .handler = ril_request_get_imei,
+ },
+ {
+ .request = RIL_REQUEST_GET_IMEISV,
+ .handler = ril_request_get_imeisv,
+ },
+ {
+ .request = RIL_REQUEST_SCREEN_STATE,
+ .handler = ril_request_screen_state,
+ },
+ /* Data */
+ {
+ .request = RIL_REQUEST_SETUP_DATA_CALL,
+ .handler = ril_request_setup_data_call,
+ },
+};
+
+unsigned int ril_request_handlers_count = sizeof(ril_request_handlers) /
+ sizeof(struct ril_request_handler);
+
+static gboolean sigterm_handler(void)
+{
+ RIL_LOGD("caught sigterm");
+
+ if (ctx != NULL && ctx->cancellable) {
+ RIL_LOGD("cancelling the current operation...");
+ g_cancellable_cancel(ctx->cancellable);
+ }
+
+ if (loop && g_main_loop_is_running (loop)) {
+ RIL_LOGD("cancelling the main loop...");
+ g_idle_add((GSourceFunc)g_main_loop_quit, loop);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+int ril_request_stats_log(void)
+{
+ struct ril_request *request;
+ struct list_head *list;
+ unsigned int pending = 0;
+ unsigned int handled = 0;
+ unsigned int unhandled = 0;
+ unsigned int count = 0;
+
+ if (ril_data == NULL)
+ return -1;
+
+ RIL_REQUEST_LOCK();
+
+ list = ril_data->requests;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ request = (struct ril_request *) list->data;
+
+ switch (request->status) {
+ case RIL_REQUEST_PENDING:
+ pending++;
+ break;
+ case RIL_REQUEST_HANDLED:
+ handled++;
+ break;
+ case RIL_REQUEST_UNHANDLED:
+ unhandled++;
+ break;
+ }
+
+ count++;
+
+ list_continue:
+ list = list->next;
+ }
+
+ RIL_LOGD("%d RIL request%s in the queue (%d pending, %d handled, %d unhandled)",
+ count, count > 1 ? "s" : "", pending, handled, unhandled);
+
+ count = 0;
+
+ list = ril_data->requests_data;
+ while (list != NULL) {
+ count++;
+
+ list = list->next;
+ }
+
+ if (count > 0)
+ RIL_LOGD("%d RIL request%s data in the queue", count, count > 1 ? "s" : "");
+
+ RIL_REQUEST_UNLOCK();
+
+ return 0;
+}
+
+int ril_request_register(int request, void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *ril_request;
+ struct list_head *list_end;
+ struct list_head *list;
+ unsigned int i;
+
+ if (ril_data == NULL)
+ return -1;
+
+ RIL_REQUEST_LOCK();
+
+ ril_request = (struct ril_request *) calloc(1, sizeof(struct ril_request));
+ ril_request->request = request;
+ ril_request->data = NULL;
+ ril_request->size = size;
+ ril_request->token = token;
+ ril_request->status = RIL_REQUEST_PENDING;
+
+ if (size > 0) {
+ ril_request->data = calloc(1, size);
+ memcpy(ril_request->data, data, size);
+ }
+
+ list_end = ril_data->requests;
+ while (list_end != NULL && list_end->next != NULL)
+ list_end = list_end->next;
+
+ list = list_head_alloc(list_end, NULL, (void *) ril_request);
+
+ if (ril_data->requests == NULL)
+ ril_data->requests = list;
+
+ RIL_REQUEST_UNLOCK();
+
+ return 0;
+}
+
+int ril_request_unregister(struct ril_request *request)
+{
+ struct list_head *list;
+ unsigned int i;
+
+ if (request == NULL || ril_data == NULL)
+ return -1;
+
+ RIL_REQUEST_LOCK();
+
+ list = ril_data->requests;
+ while (list != NULL) {
+ if (list->data == (void *) request) {
+ if (request->data != NULL && request->size > 0)
+ free(request->data);
+
+ memset(request, 0, sizeof(struct ril_request));
+ free(request);
+
+ if (list == ril_data->requests)
+ ril_data->requests = list->next;
+
+ list_head_free(list);
+
+ break;
+ }
+
+ list_continue:
+ list = list->next;
+ }
+
+ RIL_REQUEST_UNLOCK();
+
+ return 0;
+}
+
+int ril_request_flush(void)
+{
+ struct ril_request *request;
+ struct list_head *list;
+ struct list_head *list_next;
+
+ if (ril_data == NULL)
+ return -1;
+
+ RIL_REQUEST_LOCK();
+
+ list = ril_data->requests;
+ while (list != NULL) {
+ if (list->data != NULL) {
+ request = (struct ril_request *) list->data;
+
+ if (request->data != NULL && request->size > 0)
+ free(request->data);
+
+ memset(request, 0, sizeof(struct ril_request));
+ free(request);
+ }
+
+ if (list == ril_data->requests)
+ ril_data->requests = list->next;
+
+ list_next = list->next;
+
+ list_head_free(list);
+
+ list_continue:
+ list = list_next;
+ }
+
+ RIL_REQUEST_UNLOCK();
+
+ return 0;
+}
+
+struct ril_request *ril_request_find(void)
+{
+ struct ril_request *request;
+ struct list_head *list;
+
+ if (ril_data == NULL)
+ return NULL;
+
+ RIL_REQUEST_LOCK();
+
+ list = ril_data->requests;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ request = (struct ril_request *) list->data;
+
+ RIL_REQUEST_UNLOCK();
+ return request;
+
+ list_continue:
+ list = list->next;
+ }
+
+ RIL_REQUEST_UNLOCK();
+
+ return NULL;
+}
+
+struct ril_request *ril_request_find_request_status(int request, int status)
+{
+ struct ril_request *ril_request;
+ struct list_head *list;
+
+ if (ril_data == NULL)
+ return NULL;
+
+ RIL_REQUEST_LOCK();
+
+ list = ril_data->requests;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ ril_request = (struct ril_request *) list->data;
+
+ if (ril_request->request == request && ril_request->status == status) {
+ RIL_REQUEST_UNLOCK();
+ return ril_request;
+ }
+
+ list_continue:
+ list = list->next;
+ }
+
+ RIL_REQUEST_UNLOCK();
+
+ return NULL;
+}
+
+struct ril_request *ril_request_find_request(int request)
+{
+ struct ril_request *ril_request;
+ struct list_head *list;
+
+ if (ril_data == NULL)
+ return NULL;
+
+ RIL_REQUEST_LOCK();
+
+ list = ril_data->requests;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ ril_request = (struct ril_request *) list->data;
+
+ if (ril_request->request == request) {
+ RIL_REQUEST_UNLOCK();
+ return ril_request;
+ }
+
+ list_continue:
+ list = list->next;
+ }
+
+ RIL_REQUEST_UNLOCK();
+
+ return NULL;
+}
+
+struct ril_request *ril_request_find_token(RIL_Token token)
+{
+ struct ril_request *request;
+ struct list_head *list;
+
+ if (ril_data == NULL)
+ return NULL;
+
+ RIL_REQUEST_LOCK();
+
+ list = ril_data->requests;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ request = (struct ril_request *) list->data;
+
+ if (request->token == token) {
+ RIL_REQUEST_UNLOCK();
+ return request;
+ }
+
+ list_continue:
+ list = list->next;
+ }
+
+ RIL_REQUEST_UNLOCK();
+
+ return NULL;
+}
+
+struct ril_request *ril_request_find_status(int status)
+{
+ struct ril_request *request;
+ struct list_head *list;
+
+ if (ril_data == NULL)
+ return NULL;
+
+ RIL_REQUEST_LOCK();
+
+ list = ril_data->requests;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ request = (struct ril_request *) list->data;
+
+ if (request->status == status) {
+ RIL_REQUEST_UNLOCK();
+ return request;
+ }
+
+ list_continue:
+ list = list->next;
+ }
+
+ RIL_REQUEST_UNLOCK();
+
+ return NULL;
+}
+
+int ril_request_complete(RIL_Token token, RIL_Errno error, void *data,
+ size_t size)
+{
+ struct ril_request *request;
+
+ if (ril_data == NULL || ril_data->env == NULL || ril_data->env->OnRequestComplete == NULL)
+ return -1;
+
+ if (token == NULL)
+ return 0;
+
+ request = ril_request_find_token(token);
+ if (request == NULL)
+ goto complete;
+
+ ril_request_unregister(request);
+
+ ril_request_stats_log();
+
+complete:
+ ril_data->env->OnRequestComplete(token, error, data, size);
+
+ return 0;
+}
+
+int ril_request_unsolicited(int request, void *data, size_t size)
+{
+ if (ril_data == NULL || ril_data->env == NULL || ril_data->env->OnUnsolicitedResponse == NULL)
+ return -1;
+
+ ril_data->env->OnUnsolicitedResponse(request, data, size);
+
+ return 0;
+}
+
+int ril_request_timed_callback(RIL_TimedCallback callback, void *data,
+ const struct timeval *time)
+{
+ if (ril_data == NULL || ril_data->env == NULL || ril_data->env->RequestTimedCallback == NULL)
+ return -1;
+
+ ril_data->env->RequestTimedCallback(callback, data, time);
+
+ return 0;
+}
+
+int ril_request_dispatch(struct ril_request *request)
+{
+ unsigned int i;
+ int status;
+ int rc;
+
+ if (request == NULL || ril_data == NULL)
+ return -1;
+
+ for (i = 0; i < ril_request_handlers_count; i++) {
+ if (ril_request_handlers[i].handler == NULL)
+ continue;
+
+ if (ril_request_handlers[i].request == request->request) {
+ status = ril_request_handlers[i].handler(request->data, request->size, request->token);
+ switch (status) {
+ case RIL_REQUEST_PENDING:
+ case RIL_REQUEST_HANDLED:
+ case RIL_REQUEST_UNHANDLED:
+ request->status = status;
+ break;
+ case RIL_REQUEST_COMPLETED:
+ break;
+ default:
+ RIL_LOGE("Handling RIL request %d failed", request->request);
+ return -1;
+ }
+
+ return 0;
+ }
+ }
+
+ RIL_LOGD("Unhandled RIL request: %d", request->request);
+ ril_request_complete(request->token, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
+
+ return 0;
+}
+
+static gboolean ril_request_loop(gpointer data)
+{
+ struct ril_request *request;
+ int rc;
+
+ rc = all_clients_running();
+ if (rc < 0) {
+ RIL_LOGE("error during QMI client allocation");
+ return FALSE;
+ } else if (rc == 0) {
+ return TRUE;
+ }
+
+ rc = ril_radio_state_check(RADIO_STATE_OFF);
+ if (rc < 0)
+ return TRUE;
+
+ do {
+ request = ril_request_find_status(RIL_REQUEST_UNHANDLED);
+ if (request == NULL)
+ break;
+
+ request->status = RIL_REQUEST_PENDING;
+ } while (request != NULL);
+
+ do {
+ request = ril_request_find_status(RIL_REQUEST_PENDING);
+ if (request == NULL)
+ break;
+
+ rc = ril_request_dispatch(request);
+ if (rc < 0)
+ ril_request_unregister(request);
+ } while (request != NULL);
+
+ return TRUE;
+}
+
+void *ril_request_main_thread(void *data)
+{
+ int rc;
+
+ if (ril_data == NULL)
+ return NULL;
+
+ loop = g_main_loop_new(NULL, FALSE);
+
+ g_unix_signal_add(SIGTERM, (GSourceFunc) sigterm_handler, NULL);
+ g_timeout_add(100, ril_request_loop, data);
+ RIL_LOGD("RIL running main loop");
+ g_main_loop_run(loop);
+
+ RIL_LOGD("exiting main thread");
+
+ if (ctx->cancellable)
+ g_object_unref(ctx->cancellable);
+ if (ctx->DmsClient)
+ g_object_unref(ctx->DmsClient);
+ if (ctx->NasClient)
+ g_object_unref(ctx->NasClient);
+ if (ctx->UimClient)
+ g_object_unref(ctx->UimClient);
+ if (ctx->WdsClient)
+ g_object_unref(ctx->WdsClient);
+ if (ctx->device)
+ g_object_unref(ctx->device);
+ g_main_loop_unref(loop);
+ g_object_unref(ctx->file);
+
+ RIL_LOGD("cleaned up");
+ exit(EXIT_SUCCESS);
+ return NULL;
+}
+
+/*
+ * RIL request data
+ */
+
+int ril_request_data_register(int request, void *data, size_t size)
+{
+ struct ril_request_data *request_data;
+ struct list_head *list_end;
+ struct list_head *list;
+ unsigned int i;
+
+ if (data == NULL || ril_data == NULL)
+ return -1;
+
+ request_data = (struct ril_request_data *) calloc(1, sizeof(struct ril_request_data));
+ request_data->request = request;
+ request_data->data = data;
+ request_data->size = size;
+
+ list_end = ril_data->requests_data;
+ while (list_end != NULL && list_end->next != NULL)
+ list_end = list_end->next;
+
+ list = list_head_alloc(list_end, NULL, (void *) request_data);
+
+ if (ril_data->requests_data == NULL)
+ ril_data->requests_data = list;
+
+ return 0;
+}
+
+int ril_request_data_unregister(struct ril_request_data *request_data)
+{
+ struct list_head *list;
+ unsigned int i;
+
+ if (request_data == NULL || ril_data == NULL)
+ return -1;
+
+ list = ril_data->requests_data;
+ while (list != NULL) {
+ if (list->data == (void *) request_data) {
+ memset(request_data, 0, sizeof(struct ril_request_data));
+ free(request_data);
+
+ if (list == ril_data->requests_data)
+ ril_data->requests_data = list->next;
+
+ list_head_free(list);
+
+ break;
+ }
+
+ list_continue:
+ list = list->next;
+ }
+
+ return 0;
+}
+
+int ril_request_data_flush(void)
+{
+ struct ril_request_data *request_data;
+ struct list_head *list;
+ struct list_head *list_next;
+
+ if (ril_data == NULL)
+ return -1;
+
+ list = ril_data->requests_data;
+ while (list != NULL) {
+ if (list->data != NULL) {
+ request_data = (struct ril_request_data *) list->data;
+
+ if (request_data->data != NULL && request_data->size > 0)
+ free(request_data->data);
+
+ memset(request_data, 0, sizeof(struct ril_request_data));
+ free(request_data);
+ }
+
+ if (list == ril_data->requests_data)
+ ril_data->requests_data = list->next;
+
+ list_next = list->next;
+
+ list_head_free(list);
+
+ list_continue:
+ list = list_next;
+ }
+
+ return 0;
+}
+
+struct ril_request_data *ril_request_data_find_request(int request)
+{
+ struct ril_request_data *request_data;
+ struct list_head *list;
+
+ if (ril_data == NULL)
+ return NULL;
+
+ list = ril_data->requests_data;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ request_data = (struct ril_request_data *) list->data;
+
+ if (request_data->request == request)
+ return request_data;
+
+ list_continue:
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+int ril_request_data_free(int request)
+{
+ struct ril_request_data *request_data;
+
+ do {
+ request_data = ril_request_data_find_request(request);
+ if (request_data == NULL)
+ break;
+
+ if (request_data->data != NULL && request_data->size > 0)
+ free(request_data->data);
+
+ ril_request_data_unregister(request_data);
+ } while (request_data != NULL);
+
+ return 0;
+}
+
+int ril_request_data_set(int request, void *data, size_t size)
+{
+ void *buffer;
+ int rc;
+
+ if (data == NULL || size == 0)
+ return -1;
+
+ buffer = calloc(1, size);
+ memcpy(buffer, data, size);
+
+ rc = ril_request_data_register(request, buffer, size);
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int ril_request_data_set_uniq(int request, void *data, size_t size)
+{
+ int rc;
+
+ ril_request_data_free(request);
+
+ rc = ril_request_data_set(request, data, size);
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+size_t ril_request_data_size_get(int request)
+{
+ struct ril_request_data *request_data;
+
+ request_data = ril_request_data_find_request(request);
+ if (request_data == NULL)
+ return 0;
+
+ return request_data->size;
+}
+
+void *ril_request_data_get(int request)
+{
+ struct ril_request_data *request_data;
+ void *buffer;
+
+ request_data = ril_request_data_find_request(request);
+ if (request_data == NULL)
+ return NULL;
+
+ buffer = request_data->data;
+
+ ril_request_data_unregister(request_data);
+
+ return buffer;
+}
+
+/*
+ * RIL radio state
+ */
+
+int ril_radio_state_update(RIL_RadioState radio_state)
+{
+ struct ril_request *request;
+ unsigned int i;
+ int rc;
+
+ if (ril_data == NULL)
+ return -1;
+
+ if (ril_data->radio_state == radio_state)
+ return 0;
+
+ RIL_LOGD("Updating RIL radio state to %d", radio_state);
+
+ ril_data->radio_state = radio_state;
+ ril_request_unsolicited(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0);
+
+ switch (ril_data->radio_state) {
+ case RADIO_STATE_UNAVAILABLE:
+ do {
+ request = ril_request_find();
+ if (request == NULL)
+ break;
+
+ ril_request_complete(request->token, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+
+ ril_request_unregister(request);
+ } while (request != NULL);
+
+ ril_request_flush();
+ ril_request_data_flush();
+
+ ril_request_stats_log();
+
+ case RADIO_STATE_OFF:
+ RIL_LOGE("TODO: Implement ril_data_connection_flush() here!");
+
+ ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
+ ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0);
+ ril_request_unsolicited(RIL_UNSOL_DATA_CALL_LIST_CHANGED, NULL, 0);
+ ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int ril_radio_state_check(RIL_RadioState radio_state)
+{
+ RIL_RadioState radio_states[] = {
+ RADIO_STATE_UNAVAILABLE,
+ RADIO_STATE_OFF,
+ RADIO_STATE_ON,
+ RADIO_STATE_NV_NOT_READY,
+ RADIO_STATE_NV_READY,
+ RADIO_STATE_SIM_NOT_READY,
+ RADIO_STATE_SIM_LOCKED_OR_ABSENT,
+ RADIO_STATE_SIM_READY,
+ };
+ unsigned int index;
+ unsigned int count;
+ unsigned int i;
+
+ if (ril_data == NULL)
+ return -1;
+
+ count = sizeof(radio_states) / sizeof(RIL_RadioState);
+
+ for (i = 0; i < count; i++)
+ if (radio_states[i] == radio_state)
+ break;
+
+ index = i;
+
+ for (i = 0; i < count; i++)
+ if (radio_states[i] == ril_data->radio_state)
+ break;
+
+ if (i < index)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * RIL data
+ */
+
+int ril_data_create(void)
+{
+ ril_data = (struct ril_data *) calloc(1, sizeof(struct ril_data));
+
+ pthread_mutex_init(&ril_data->request_mutex, NULL);
+
+ RIL_LOGD("initializing RIL data");
+
+ ril_data->radio_state = RADIO_STATE_UNAVAILABLE;
+ /* modem is booting in ethernet mode */
+ ril_data->data_connection.raw_ip_mode = FALSE;
+
+ return 0;
+}
+
+int ril_data_destroy(void)
+{
+ RIL_LOGD("destroying RIL data");
+
+ if (ril_data == NULL)
+ return -1;
+
+ pthread_mutex_destroy(&ril_data->request_mutex);
+
+ free(ril_data);
+ ril_data = NULL;
+
+ return 0;
+}
+
+/*
+ * RIL interface
+ */
+
+void ril_on_request(int request, void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *ril_request;
+ void *buffer = NULL;
+ unsigned int strings_count = 0;
+ unsigned int i;
+ char *c;
+
+ ril_request = ril_request_find_token(token);
+ if (ril_request != NULL)
+ ril_request_unregister(ril_request);
+
+ switch (request) {
+ case RIL_REQUEST_DIAL:
+ if (data == NULL || size < sizeof(RIL_Dial))
+ break;
+
+ buffer = calloc(1, size);
+
+ memcpy(buffer, data, size);
+
+ if (((RIL_Dial *) data)->address != NULL)
+ ((RIL_Dial *) buffer)->address = strdup(((RIL_Dial *) data)->address);
+
+ data = buffer;
+ break;
+ case RIL_REQUEST_WRITE_SMS_TO_SIM:
+ if (data == NULL || size < sizeof(RIL_SMS_WriteArgs))
+ break;
+
+
+ buffer = calloc(1, size);
+
+ memcpy(buffer, data, size);
+
+ if (((RIL_SMS_WriteArgs *) data)->pdu != NULL)
+ ((RIL_SMS_WriteArgs *) buffer)->pdu = strdup(((RIL_SMS_WriteArgs *) data)->pdu);
+
+ if (((RIL_SMS_WriteArgs *) data)->smsc != NULL)
+ ((RIL_SMS_WriteArgs *) buffer)->smsc = strdup(((RIL_SMS_WriteArgs *) data)->smsc);
+
+ data = buffer;
+ break;
+ case RIL_REQUEST_SEND_SMS:
+ case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
+ case RIL_REQUEST_QUERY_FACILITY_LOCK:
+ case RIL_REQUEST_SET_FACILITY_LOCK:
+ case RIL_REQUEST_ENTER_SIM_PIN:
+ case RIL_REQUEST_ENTER_SIM_PUK:
+ case RIL_REQUEST_ENTER_SIM_PIN2:
+ case RIL_REQUEST_ENTER_SIM_PUK2:
+ case RIL_REQUEST_CHANGE_SIM_PIN:
+ case RIL_REQUEST_CHANGE_SIM_PIN2:
+ strings_count = size / sizeof(char *);
+ break;
+ case RIL_REQUEST_SIM_IO:
+ if (data == NULL || size < sizeof(RIL_SIM_IO_v6))
+ break;
+
+ buffer = calloc(1, size);
+
+ memcpy(buffer, data, size);
+
+ if (((RIL_SIM_IO_v6 *) data)->path != NULL)
+ ((RIL_SIM_IO_v6 *) buffer)->path = strdup(((RIL_SIM_IO_v6 *) data)->path);
+
+ if (((RIL_SIM_IO_v6 *) data)->data != NULL)
+ ((RIL_SIM_IO_v6 *) buffer)->data = strdup(((RIL_SIM_IO_v6 *) data)->data);
+
+ if (((RIL_SIM_IO_v6 *) data)->pin2 != NULL)
+ ((RIL_SIM_IO_v6 *) buffer)->pin2 = strdup(((RIL_SIM_IO_v6 *) data)->pin2);
+
+ if (((RIL_SIM_IO_v6 *) data)->aidPtr != NULL)
+ ((RIL_SIM_IO_v6 *) buffer)->aidPtr = strdup(((RIL_SIM_IO_v6 *) data)->aidPtr);
+
+ data = buffer;
+ break;
+ case RIL_REQUEST_SETUP_DATA_CALL:
+ case RIL_REQUEST_DEACTIVATE_DATA_CALL:
+ strings_count = size / sizeof(char *);
+ break;
+ default:
+ if (data == NULL || size != sizeof(char *))
+ break;
+
+ c = (char *) data;
+
+ for (i = 0; isprint(c[i]); i++);
+
+ if (i > 0 && c[i] == '\0') {
+ size = i + 1;
+ RIL_LOGD("Detected string with a size of %d byte%s", size, size > 0 ? "s" : "");
+ }
+
+ break;
+ }
+
+ if (strings_count > 0 && data != NULL && size >= strings_count * sizeof(char *)) {
+ buffer = calloc(1, size);
+
+ for (i = 0; i < strings_count; i++) {
+ if (((char **) data)[i] != NULL) {
+ c = strdup(((char **) data)[i]);
+ ((char **) buffer)[i] = c;
+ }
+ }
+
+ data = buffer;
+ }
+
+ ril_request_register(request, data, size, token);
+
+ if (buffer != NULL)
+ free(buffer);
+
+ ril_request_stats_log();
+}
+
+
+RIL_RadioState ril_on_state_request(void)
+{
+ if (ril_data == NULL)
+ return RADIO_STATE_UNAVAILABLE;
+
+ return ril_data->radio_state;
+}
+
+int ril_supports(int request)
+{
+ unsigned int i;
+
+ for (i = 0; i < ril_request_handlers_count; i++) {
+ if (ril_request_handlers[i].handler == NULL)
+ continue;
+
+ if (ril_request_handlers[i].request == request)
+ return 1;
+ }
+
+ return 0;
+}
+
+void ril_on_cancel(RIL_Token token)
+{
+ struct ril_request *request;
+
+ request = ril_request_find_token(token);
+ if (request == NULL)
+ return;
+
+ ril_request_unregister(request);
+
+ ril_request_stats_log();
+}
+
+const char *ril_get_version(void)
+{
+ return RIL_VERSION_STRING;
+}
+
+RIL_RadioFunctions ril_radio_functions = {
+ RIL_VERSION,
+ ril_on_request,
+ ril_on_state_request,
+ ril_supports,
+ ril_on_cancel,
+ ril_get_version
+};
+
+const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc,
+ char **argv)
+{
+ RIL_RadioFunctions *radio_functions;
+ pthread_attr_t attr;
+ int rc;
+
+ if (env == NULL)
+ return NULL;
+
+ rc = ril_data_create();
+ if (rc < 0) {
+ RIL_LOGE("Creating RIL data failed");
+ return NULL;
+ }
+
+ ril_data->env = env;
+
+ RIL_LOGD("creating RIL clients");
+
+ rc = create_qmi_clients();
+ if (rc < 0) {
+ RIL_LOGE("Creating QMI clients failed");
+ goto error;
+ }
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ rc = pthread_create(&ril_data->request_thread, &attr, ril_request_main_thread, NULL);
+ if (rc != 0) {
+ RIL_LOGE("Starting request main thread failed");
+ goto error;
+ }
+
+ radio_functions = &ril_radio_functions;
+ goto complete;
+
+error:
+ radio_functions = NULL;
+
+complete:
+ return radio_functions;
+}
diff --git a/qmi-ril.h b/qmi-ril.h
new file mode 100644
index 0000000..b32705a
--- /dev/null
+++ b/qmi-ril.h
@@ -0,0 +1,253 @@
+/*
+ * This file is part of QMI-RIL.
+ *
+ * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com>
+ * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr>
+ * 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/>.
+ */
+
+#ifndef _QMI_RIL_H_
+#define _QMI_RIL_H_
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <glib.h>
+#include <libqmi-glib.h>
+
+#include <telephony/ril.h>
+
+#include <utils.h>
+
+/*
+ * Values
+ */
+
+#define RIL_VERSION_STRING "QMI-RIL"
+
+/*
+ * Macros
+ */
+
+#ifdef ALOGI
+#define RIL_LOGI ALOGI
+#else
+#define RIL_LOGI LOGI
+#endif
+
+#ifdef ALOGD
+#define RIL_LOGD ALOGD
+#else
+#define RIL_LOGD LOGD
+#endif
+
+#ifdef ALOGE
+#define RIL_LOGE ALOGE
+#else
+#define RIL_LOGE LOGE
+#endif
+
+#define RIL_REQUEST_LOCK() pthread_mutex_lock(&ril_data->request_mutex)
+#define RIL_REQUEST_UNLOCK() pthread_mutex_unlock(&ril_data->request_mutex)
+
+/*
+ * RIL request
+ */
+
+enum {
+ RIL_REQUEST_PENDING,
+ RIL_REQUEST_HANDLED,
+ RIL_REQUEST_UNHANDLED,
+ RIL_REQUEST_COMPLETED,
+};
+
+struct ril_request_handler {
+ int request;
+ int (*handler)(void *data, size_t size, RIL_Token token);
+};
+
+struct ril_request {
+ int request;
+ void *data;
+ size_t size;
+ RIL_Token token;
+
+ int status;
+};
+
+extern struct ril_request_handler ril_request_handlers[];
+extern unsigned int ril_request_handlers_count;
+
+int ril_request_register(int request, void *data, size_t size, RIL_Token token);
+int ril_request_unregister(struct ril_request *request);
+int ril_request_flush(void);
+struct ril_request *ril_request_find(void);
+struct ril_request *ril_request_find_request_status(int request, int status);
+struct ril_request *ril_request_find_request(int request);
+struct ril_request *ril_request_find_token(RIL_Token token);
+struct ril_request *ril_request_find_status(int status);
+int ril_request_complete(RIL_Token token, RIL_Errno error, void *data,
+ size_t size);
+int ril_request_unsolicited(int request, void *data, size_t size);
+int ril_request_timed_callback(RIL_TimedCallback callback, void *data,
+ const struct timeval *time);
+
+/*
+ * RIL request data
+ */
+
+struct ril_request_data {
+ int request;
+ void *data;
+ size_t size;
+};
+
+int ril_request_data_register(int request, void *data, size_t size);
+int ril_request_data_unregister(struct ril_request_data *request_data);
+int ril_request_data_flush(void);
+struct ril_request_data *ril_request_data_find_request(int request);
+int ril_request_data_free(int request);
+int ril_request_data_set(int request, void *data, size_t size);
+int ril_request_data_set_uniq(int request, void *data, size_t size);
+size_t ril_request_data_size_get(int request);
+void *ril_request_data_get(int request);
+
+/*
+ * RIL radio state
+ */
+
+int ril_radio_state_update(RIL_RadioState radio_state);
+int ril_radio_state_check(RIL_RadioState radio_state);
+
+/*
+ * RIL data
+ */
+
+struct ril_data_connection {
+ guint32 packet_data_handle;
+
+ gboolean raw_ip_mode;
+ int status;
+ int active;
+
+ const char *iface;
+ char *type;
+ char *ip_addr;
+ char *subnet_mask;
+ char *gateway;
+ char *dns1;
+ char *dns2;
+};
+
+struct ril_data {
+ const struct RIL_Env *env;
+
+ RIL_RadioState radio_state;
+ char *sim_pin;
+
+ struct list_head *requests;
+ struct list_head *requests_data;
+
+ struct ril_data_connection data_connection;
+
+ pthread_t request_thread;
+ pthread_mutex_t request_mutex;
+};
+
+extern struct ril_data *ril_data;
+
+int ril_data_create(void);
+int ril_data_destroy(void);
+
+/* Context */
+typedef struct {
+ GFile *file;
+ QmiDevice *device;
+ QmiClientDms *DmsClient;
+ QmiClientNas *NasClient;
+ QmiClientUim *UimClient;
+ QmiClientWds *WdsClient;
+ QmiClientWda *WdaClient;
+ GCancellable *cancellable;
+
+ guint dms_event_report_indication_id;
+ guint serving_system_indication_id;
+ guint nas_event_report_indication_id;
+ guint packet_status_timeout_id;
+} Context;
+Context *ctx;
+
+int create_qmi_clients(void);
+int all_clients_running(void);
+
+/*
+ * Power
+ */
+
+void dms_event_report_indication_cb(QmiClientDms *client,
+ QmiIndicationDmsEventReportOutput *output);
+int ril_request_radio_power(void *data, size_t size, RIL_Token token);
+
+/*
+ * Call
+ */
+
+int ril_request_get_current_calls(void *data, size_t size, RIL_Token token);
+
+/*
+ * SIM
+ */
+
+int ril_request_get_sim_status(void *data, size_t size, RIL_Token token);
+int ril_request_query_facility_lock(void *data, size_t size, RIL_Token token);
+int ril_request_sim_io(void *data, size_t size, RIL_Token token);
+
+/*
+ * Network
+ */
+
+void serving_system_indication_cb(QmiClientNas *client,
+ QmiIndicationNasServingSystemOutput *output);
+void nas_event_report_indication_cb(QmiClientNas *client,
+ QmiIndicationNasEventReportOutput *output);
+int ril_request_signal_strength(void *data, size_t size, RIL_Token token);
+int ril_request_query_network_selection_mode(void *data, size_t size,
+ RIL_Token token);
+int ril_request_operator(void *data, size_t size, RIL_Token token);
+int ril_request_registration_state(void *data, size_t size,
+ RIL_Token token);
+int ril_request_set_preferred_network_type(void *data, size_t size,
+ RIL_Token token);
+void qmi_set_raw_ip_mode(void);
+
+/*
+ * Misc
+ */
+
+int ril_request_baseband_version(void *data, size_t size, RIL_Token token);
+int ril_request_get_imsi(void *data, size_t size, RIL_Token token);
+int ril_request_get_imei(void *data, size_t size, RIL_Token token);
+int ril_request_get_imeisv(void *data, size_t size, RIL_Token token);
+int ril_request_screen_state(void *data, size_t size, RIL_Token token);
+
+/*
+ * Data
+ */
+
+int ril_request_setup_data_call(void *data, size_t size, RIL_Token token);
+
+#endif
diff --git a/sim.c b/sim.c
new file mode 100644
index 0000000..aaeb1f3
--- /dev/null
+++ b/sim.c
@@ -0,0 +1,695 @@
+/*
+ * 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 <qmi-ril.h>
+#include <sim.h>
+
+RIL_RadioState qmi2ril_pin_status_response(QmiDmsUimPinStatus pin_status,
+ RIL_CardStatus_v6 *card_status)
+{
+ RIL_AppStatus app_statuses[] = {
+ // Absent
+ { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+ // Not ready
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+ // Ready
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+ // PIN lock
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+ // PUK lock
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
+ // PUK locked
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_PERM_BLOCKED, RIL_PINSTATE_UNKNOWN },
+ };
+ RIL_RadioState radio_state;
+ unsigned int index;
+ unsigned int count;
+
+ count = sizeof(app_statuses) / sizeof(RIL_AppStatus);
+
+ switch (pin_status) {
+ case QMI_DMS_UIM_PIN_STATUS_NOT_INITIALIZED:
+ index = 0;
+ break;
+ case QMI_DMS_UIM_PIN_STATUS_ENABLED_NOT_VERIFIED:
+ index = 3;
+ break;
+ case QMI_DMS_UIM_PIN_STATUS_ENABLED_VERIFIED:
+ case QMI_DMS_UIM_PIN_STATUS_DISABLED:
+ index = 2;
+ break;
+ default:
+ index = 0;
+ }
+
+ switch (index) {
+ case 1:
+ radio_state = RADIO_STATE_SIM_NOT_READY;
+ break;
+ case 2:
+ radio_state = RADIO_STATE_SIM_READY;
+ break;
+ default:
+ radio_state = RADIO_STATE_SIM_LOCKED_OR_ABSENT;
+ }
+
+ memset(card_status, 0, sizeof(RIL_CardStatus_v6));
+
+ if (index == 0)
+ card_status->card_state = RIL_CARDSTATE_ABSENT;
+ else
+ card_status->card_state = RIL_CARDSTATE_PRESENT;
+
+ card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
+
+ card_status->cdma_subscription_app_index = -1;
+ card_status->ims_subscription_app_index = -1;
+
+ memcpy((void *) &card_status->applications[0], (void *) &app_statuses[index], sizeof(RIL_AppStatus));
+
+ card_status->gsm_umts_subscription_app_index = 0;
+ card_status->num_applications = 1;
+
+ RIL_LOGD("%s: Selecting status application %d on %d", __func__,
+ index, count);
+
+ return radio_state;
+}
+
+static void uim_get_pin_status_ready(QmiClientDms *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ RIL_CardStatus_v6 card_status;
+ RIL_RadioState radio_state;
+ guint8 verify_retries_left;
+ guint8 unblock_retries_left;
+ QmiDmsUimPinStatus pin1_status;
+ QmiDmsUimPinStatus pin2_status;
+ QmiMessageDmsUimGetPinStatusOutput *output;
+ GError *error = NULL;
+ int rc;
+
+ output = qmi_client_dms_uim_get_pin_status_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_dms_uim_get_pin_status_output_get_result(output, &error)) {
+ RIL_LOGE("error: couldn't get PIN status: %s", error->message);
+
+ // assume not initialized
+ pin1_status = QMI_DMS_UIM_PIN_STATUS_NOT_INITIALIZED;
+ goto evaluation;
+ }
+
+ RIL_LOGD("PIN status retrieved successfully");
+
+ if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status (
+ output, &pin1_status, &verify_retries_left,
+ &unblock_retries_left, NULL)) {
+ RIL_LOGD("PIN1:\n"
+ "\tStatus: %s\n"
+ "\tVerify: %u\n"
+ "\tUnblock: %u",
+ qmi_dms_uim_pin_status_get_string(pin1_status),
+ verify_retries_left, unblock_retries_left);
+ }
+
+ if (qmi_message_dms_uim_get_pin_status_output_get_pin2_status(
+ output, &pin2_status, &verify_retries_left,
+ &unblock_retries_left, NULL)) {
+ RIL_LOGD("PIN2:\n"
+ "\tStatus: %s\n"
+ "\tVerify: %u\n"
+ "\tUnblock: %u",
+ qmi_dms_uim_pin_status_get_string(pin2_status),
+ verify_retries_left, unblock_retries_left);
+ }
+
+evaluation:
+ radio_state = qmi2ril_pin_status_response(pin1_status, &card_status);
+
+ if (radio_state == 0)
+ goto error;
+
+ ril_radio_state_update(radio_state);
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &card_status, sizeof(card_status));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_dms_uim_get_pin_status_output_unref(output);
+}
+
+int ril_request_get_sim_status(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ request = ril_request_find_request_status(RIL_REQUEST_GET_SIM_STATUS, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ qmi_client_dms_uim_get_pin_status(ctx->DmsClient, NULL, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)uim_get_pin_status_ready,
+ token);
+
+ return RIL_REQUEST_HANDLED;
+}
+
+int ril_request_query_facility_lock(void *data, size_t size, RIL_Token token)
+{
+ int active;
+ int rc;
+
+ if (data == NULL || size < 4 * sizeof(char *))
+ goto error;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ RIL_LOGE("%s: TODO: implement me!", __func__);
+ // let's assume it's inactive
+ // corresponding libqmi call fails with my SIM card, so I
+ // can't test it anyway
+ active = 0;
+ ril_request_complete(token, RIL_E_SUCCESS, &active, sizeof(active));
+
+ rc = RIL_REQUEST_COMPLETED;
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ rc = RIL_REQUEST_COMPLETED;
+
+complete:
+ return rc;
+}
+
+static void read_transparent_ready(QmiClientUim *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageUimReadTransparentOutput *output;
+ GError *error = NULL;
+ guint8 sw1 = 0;
+ guint8 sw2 = 0;
+ GArray *read_result = NULL;
+ gchar *str = NULL;
+ RIL_SIM_IO_Response response;
+
+ response.simResponse = NULL;
+
+ output = qmi_client_uim_read_transparent_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_uim_read_transparent_output_get_result(
+ output, &error)) {
+ RIL_LOGE("error: couldn't read transparent file from the UIM: %s",
+ error->message);
+ goto card_result;
+ }
+
+ RIL_LOGD("successfully read information from the UIM");
+
+ /* Read result */
+ if (qmi_message_uim_read_transparent_output_get_read_result(
+ output, &read_result, NULL)) {
+ str = array2string(read_result);
+ RIL_LOGD("Read result:\n"
+ "%s", str);
+
+ response.simResponse = str;
+ }
+
+card_result:
+ if (qmi_message_uim_read_transparent_output_get_card_result(
+ output, &sw1, &sw2,
+ NULL)) {
+ RIL_LOGD("Card result:\n"
+ "\tSW1: '0x%02x'\n"
+ "\tSW2: '0x%02x'", sw1, sw2);
+ response.sw1 = sw1;
+ response.sw2 = sw2;
+ } else
+ goto error;
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &response, sizeof(response));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (str)
+ g_free(str);
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_uim_read_transparent_output_unref(output);
+}
+
+static void read_record_ready(QmiClientUim *client, GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageUimReadRecordOutput *output;
+ GError *error = NULL;
+ guint8 sw1 = 0;
+ guint8 sw2 = 0;
+ GArray *read_result = NULL;
+ gchar *str = NULL;
+ RIL_SIM_IO_Response response;
+
+ response.simResponse = NULL;
+
+ output = qmi_client_uim_read_record_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_uim_read_record_output_get_result(
+ output, &error)) {
+ RIL_LOGE("error: couldn't read record file from the UIM: %s",
+ error->message);
+
+ goto card_result;
+ }
+
+ RIL_LOGD("successfully read information from the UIM");
+
+ /* Read result */
+ if (qmi_message_uim_read_record_output_get_read_result(
+ output, &read_result, NULL)) {
+ str = array2string(read_result);
+ RIL_LOGD("Read result:\n"
+ "%s", str);
+
+ response.simResponse = str;
+ }
+
+card_result:
+ if (qmi_message_uim_read_record_output_get_card_result(
+ output, &sw1, &sw2, NULL)) {
+ RIL_LOGD("Card result:\n"
+ "\tSW1: '0x%02x'\n"
+ "\tSW2: '0x%02x'", sw1, sw2);
+ response.sw1 = sw1;
+ response.sw2 = sw2;
+ } else
+ goto error;
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &response, sizeof(response));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (str)
+ g_free(str);
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_uim_read_record_output_unref(output);
+}
+
+static void get_file_attributes_ready(QmiClientUim *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageUimGetFileAttributesOutput *output;
+ GError *error = NULL;
+ guint8 sw1 = 0;
+ guint8 sw2 = 0;
+ guint16 file_size, file_id;
+ QmiUimFileType file_type;
+ guint16 record_size;
+ guint16 record_count;
+ struct sim_file_response sim_file_response;
+ RIL_SIM_IO_Response response;
+
+ memset(&sim_file_response, 0, sizeof(sim_file_response));
+ response.simResponse = NULL;
+
+ output = qmi_client_uim_get_file_attributes_finish(client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s\n", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_uim_get_file_attributes_output_get_result(output, &error)) {
+ RIL_LOGE("error: couldn't get file attributes from the UIM: %s",
+ error->message);
+
+ goto card_result;
+ }
+
+ RIL_LOGD("Successfully got file attributes from the UIM");
+
+ if (qmi_message_uim_get_file_attributes_output_get_file_attributes(
+ output,
+ &file_size, &file_id, &file_type, &record_size,
+ &record_count, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL)) {
+
+ RIL_LOGD("File attributes:\n"
+ "\tFile size: %u\n"
+ "\tFile ID: %u\n"
+ "\tFile type: %s\n"
+ "\tRecord size: %u\n"
+ "\tRecord count: %u", (guint)file_size,
+ (guint)file_id, qmi_uim_file_type_get_string(file_type),
+ (guint)record_size, (guint)record_count);
+
+ sim_file_response.file_size = file_size;
+ sim_file_response.file_id = file_id;
+ sim_file_response.access_condition[0] = 0x00;
+ sim_file_response.access_condition[1] = 0xff;
+ sim_file_response.access_condition[2] = 0xff;
+
+ sim_file_response.file_status = 0x01;
+ sim_file_response.file_length = 0x02;
+
+ switch (file_type) {
+ case QMI_UIM_FILE_TYPE_TRANSPARENT:
+ sim_file_response.file_type = SIM_FILE_TYPE_EF;
+ sim_file_response.file_structure = SIM_FILE_STRUCTURE_TRANSPARENT;
+ break;
+ case QMI_UIM_FILE_TYPE_DEDICATED_FILE:
+ sim_file_response.file_type = SIM_FILE_TYPE_DF;
+ sim_file_response.file_structure = SIM_FILE_STRUCTURE_LINEAR_FIXED;
+ break;
+ case QMI_UIM_FILE_TYPE_MASTER_FILE:
+ sim_file_response.file_type = SIM_FILE_TYPE_MF;
+ sim_file_response.file_structure = SIM_FILE_STRUCTURE_LINEAR_FIXED;
+ break;
+ case QMI_UIM_FILE_TYPE_LINEAR_FIXED:
+ default:
+ sim_file_response.file_type = SIM_FILE_TYPE_EF;
+ sim_file_response.file_structure = SIM_FILE_STRUCTURE_LINEAR_FIXED;
+ }
+
+ sim_file_response.record_length = record_size;
+ response.simResponse = data2string((void *) &sim_file_response, sizeof(sim_file_response));
+ }
+
+card_result:
+ if (qmi_message_uim_get_file_attributes_output_get_card_result(
+ output, &sw1, &sw2, NULL)) {
+ RIL_LOGD("Card result:\n"
+ "\tSW1: '0x%02x'\n"
+ "\tSW2: '0x%02x'", sw1, sw2);
+ response.sw1 = sw1;
+ response.sw2 = sw2;
+ } else {
+ // assume file wasn't found
+ response.sw1 = 0x6a;
+ response.sw2 = 0x82;
+ }
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &response, sizeof(response));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (response.simResponse != NULL)
+ free(response.simResponse);
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_uim_get_file_attributes_output_unref(output);
+}
+
+int ril2qmi_sim_file_path(const gchar *file_path_str, GArray **file_path)
+{
+ guint str_len;
+ guint array_elements;
+ gchar str_item[4];
+ gulong path_item;
+ guint8 val;
+ guint i;
+
+ str_len = strlen(file_path_str);
+
+ if (str_len == 0) {
+ // assume it's 3F00 (root file)
+ file_path_str = "3F00";
+ str_len = 4;
+ } else if (str_len < 4 || str_len % 2 != 0) {
+ RIL_LOGE("file path error: len %d string %s", str_len,
+ file_path_str);
+ return -1;
+ }
+
+ array_elements = strlen(file_path_str) / 4;
+
+ *file_path = g_array_sized_new(FALSE, FALSE, sizeof (guint8),
+ array_elements);
+
+ for (i = 0; i < array_elements; i++) {
+ strncpy(str_item, &file_path_str[i*4], 4);
+ path_item = (strtoul(str_item, NULL, 16)) & 0xFFFF;
+
+ val = path_item & 0xFF;
+ g_array_append_val(*file_path, val);
+ val = (path_item >> 8) & 0xFF;
+ g_array_append_val(*file_path, val);
+ }
+
+ return 0;
+}
+
+int ril2qmi_get_attributes(RIL_SIM_IO_v6 *sim_io, RIL_Token token)
+{
+ QmiMessageUimGetFileAttributesInput *input;
+ GArray *file_path = NULL;
+ int rc;
+
+ rc = ril2qmi_sim_file_path(sim_io->path, &file_path);
+ if (rc < 0) {
+ RIL_LOGE("%s: error extracting file path", __func__);
+ return -1;
+ }
+
+ input = qmi_message_uim_get_file_attributes_input_new();
+ qmi_message_uim_get_file_attributes_input_set_session_information(
+ input, QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING,
+ "", NULL);
+ qmi_message_uim_get_file_attributes_input_set_file(
+ input, sim_io->fileid, file_path, NULL);
+
+ qmi_client_uim_get_file_attributes(ctx->UimClient, input, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_file_attributes_ready,
+ token);
+
+ qmi_message_uim_get_file_attributes_input_unref(input);
+ g_array_unref(file_path);
+
+ return 0;
+}
+
+int ril2qmi_read_record(RIL_SIM_IO_v6 *sim_io, RIL_Token token)
+{
+ QmiMessageUimReadRecordInput *input;
+ GArray *file_path = NULL;
+ int rc;
+
+ rc = ril2qmi_sim_file_path(sim_io->path, &file_path);
+ if (rc < 0) {
+ RIL_LOGE("%s: error extracting file path", __func__);
+ return -1;
+ }
+
+ input = qmi_message_uim_read_record_input_new();
+ qmi_message_uim_read_record_input_set_session_information(
+ input, QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING,
+ "", NULL);
+ qmi_message_uim_read_record_input_set_file(
+ input, sim_io->fileid, file_path, NULL);
+ qmi_message_uim_read_record_input_set_record(
+ input,sim_io->p1, sim_io->p3, NULL);
+ g_array_unref(file_path);
+
+ qmi_client_uim_read_record(ctx->UimClient, input, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)read_record_ready,
+ token);
+
+ qmi_message_uim_read_record_input_unref(input);
+ return 0;
+}
+
+int ril2qmi_read_transparent(RIL_SIM_IO_v6 *sim_io, RIL_Token token)
+{
+ QmiMessageUimReadTransparentInput *input;
+ GArray *file_path = NULL;
+ int rc;
+
+ rc = ril2qmi_sim_file_path(sim_io->path, &file_path);
+ if (rc < 0) {
+ RIL_LOGE("%s: error extracting file path", __func__);
+ return -1;
+ }
+
+ input = qmi_message_uim_read_transparent_input_new();
+ qmi_message_uim_read_transparent_input_set_session_information(
+ input, QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING,
+ "", NULL);
+ qmi_message_uim_read_transparent_input_set_file(input,
+ sim_io->fileid,
+ file_path, NULL);
+ qmi_message_uim_read_transparent_input_set_read_information(
+ input,
+ // p1 is offset high, p2 is offset low, which one is it?
+ sim_io->p1,
+ sim_io->p3, NULL);
+ g_array_unref (file_path);
+
+ qmi_client_uim_read_transparent(ctx->UimClient, input, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)read_transparent_ready,
+ token);
+
+ qmi_message_uim_read_transparent_input_unref(input);
+ return 0;
+}
+
+int ril_request_sim_io(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ RIL_SIM_IO_v6 *sim_io = NULL;
+ int rc;
+
+ if (data == NULL || size < sizeof(RIL_SIM_IO_v6))
+ goto error;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
+ if (rc < 0) {
+ rc = ril_radio_state_check(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+ else
+ RIL_LOGE("%s: SIM is locked or absent.", __func__);
+ }
+
+ request = ril_request_find_request_status(RIL_REQUEST_SIM_IO, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ sim_io = (RIL_SIM_IO_v6 *) data;
+
+ if (sim_io->data != NULL) {
+ RIL_LOGE("TODO: implement processing for data %s",
+ sim_io->data);
+ }
+
+ if (sim_io->pin2 != NULL) {
+ RIL_LOGE("TODO: implement PIN2 unlock first for PIN %s",
+ sim_io->pin2);
+ }
+
+ switch (sim_io->command) {
+ case SIM_COMMAND_GET_RESPONSE:
+ RIL_LOGD("get response command");
+ rc = ril2qmi_get_attributes(sim_io, token);
+ if (rc < 0)
+ goto error;
+ break;
+ case SIM_COMMAND_READ_BINARY:
+ RIL_LOGD("read binary command");
+ rc = ril2qmi_read_transparent(sim_io, token);
+ if (rc < 0)
+ goto error;
+
+ break;
+ case SIM_COMMAND_READ_RECORD:
+ RIL_LOGD("read record command");
+ rc = ril2qmi_read_record(sim_io, token);
+ if (rc < 0)
+ goto error;
+
+ break;
+ case SIM_COMMAND_UPDATE_BINARY:
+ case SIM_COMMAND_UPDATE_RECORD:
+ case SIM_COMMAND_SEEK:
+ default:
+ RIL_LOGD("%s: command %d not supported", __func__,
+ sim_io->command);
+ goto error;
+ }
+
+ rc = RIL_REQUEST_HANDLED;
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ rc = RIL_REQUEST_COMPLETED;
+
+complete:
+ if (sim_io != NULL) {
+ if (sim_io->path != NULL)
+ free(sim_io->path);
+
+ if (sim_io->data != NULL)
+ free(sim_io->data);
+
+ if (sim_io->pin2 != NULL)
+ free(sim_io->pin2);
+
+ if (sim_io->aidPtr != NULL)
+ free(sim_io->aidPtr);
+ }
+
+ return rc;
+}
diff --git a/utils.c b/utils.c
new file mode 100644
index 0000000..50e0330
--- /dev/null
+++ b/utils.c
@@ -0,0 +1,144 @@
+/*
+ * This file is part of QMI-RIL.
+ *
+ * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com>
+ * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr>
+ * 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/>.
+ */
+
+#define LOG_TAG "RIL"
+#include <utils/Log.h>
+
+#include <utils.h>
+
+struct list_head *list_head_alloc(struct list_head *prev, struct list_head *next,
+ const void *data)
+{
+ struct list_head *list;
+
+ list = calloc(1, sizeof(struct list_head));
+ list->data = data;
+ list->prev = prev;
+ list->next = next;
+
+ if (prev != NULL)
+ prev->next = list;
+ if (next != NULL)
+ next->prev = list;
+
+ return list;
+}
+
+void list_head_free(struct list_head *list)
+{
+ if (list == NULL)
+ return;
+
+ if (list->next != NULL)
+ list->next->prev = list->prev;
+ if (list->prev != NULL)
+ list->prev->next = list->next;
+
+ memset(list, 0, sizeof(struct list_head));
+ free(list);
+}
+
+int strings_array_free(char **array, size_t size)
+{
+ unsigned int count;
+ unsigned int i;
+
+ if (array == NULL)
+ return -1;
+
+ if (size == 0) {
+ for (i = 0; array[i] != NULL; i++)
+ free(array[i]);
+ } else {
+ count = size / sizeof(char *);
+ if (count == 0)
+ return -1;
+
+ for (i = 0; i < count; i++) {
+ if (array[i] != NULL)
+ free(array[i]);
+ }
+ }
+
+ return 0;
+}
+
+gchar *array2string(const GArray *data)
+{
+ gsize i, j;
+ gsize new_str_length;
+ char *new_str;
+
+ if (!data)
+ return g_strdup("");
+
+ new_str_length = 2 * data->len;
+
+ new_str = (char *) calloc(1, new_str_length);
+
+ // print hexadecimal representation of each byte
+ for (i = 0, j = 0; i < data->len; i++) {
+ sprintf(&new_str[j], "%02X", g_array_index(data,
+ guint8,
+ i));
+ j+=2;
+ }
+
+ return new_str;
+}
+
+size_t data2string_length(const void *data, size_t size)
+{
+ size_t length;
+
+ if (data == NULL || size == 0)
+ return 0;
+
+ length = size * 2 + 1;
+
+ return length;
+}
+
+char *data2string(const void *data, size_t size)
+{
+ char *string;
+ size_t length;
+ char *p;
+ size_t i;
+
+ if (data == NULL || size == 0)
+ return NULL;
+
+ length = data2string_length(data, size);
+ if (length == 0)
+ return NULL;
+
+ string = (char *) calloc(1, length);
+
+ p = string;
+
+ for (i = 0; i < size; i++) {
+ sprintf(p, "%02x", *((unsigned char *) data + i));
+ p += 2 * sizeof(char);
+ }
+
+ return string;
+}
diff --git a/utils.h b/utils.h
new file mode 100644
index 0000000..2bd14fb
--- /dev/null
+++ b/utils.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of QMI-RIL.
+ *
+ * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com>
+ * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr>
+ * 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/>.
+ */
+
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+#include <qmi-ril.h>
+
+struct list_head {
+ struct list_head *prev;
+ struct list_head *next;
+ const void *data;
+};
+
+struct list_head *list_head_alloc(struct list_head *prev, struct list_head *next,
+ const void *data);
+void list_head_free(struct list_head *list);
+int strings_array_free(char **array, size_t size);
+gchar *array2string(const GArray *data);
+char *data2string(const void *data, size_t size);
+
+#endif