summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-09-05 22:19:36 (GMT)
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-09-05 22:19:36 (GMT)
commitf35a9bbd1ebb52433f313c675fbe01bb1ca96d7d (patch)
treec1aff224fd4a2ea2e5e06805c7caff5406b0ab42
parent06cf4fe68ad096961b4b9c653ba2bc31d270f009 (diff)
downloadqmi-ril-master.zip
qmi-ril-master.tar.gz
qmi-ril-master.tar.bz2
initial version of QMI-RILHEADmaster
The RIL uses libqmi. qmicli and ModemManager were used as references for using libqmi. The request processing is modelled after Samsung-RIL and a lot of code could be reused for QMI-RIL. Establishing a data connection succeeds and mobile data is working in early testing. However, there is not yet a routine for handling interruptions and notifying Android about them. Information about the serving network including signal strength are retrieved and an unlocked SIM card is recognized. Reading data from the SIM and requesting the usual device information should work as well. Support for voice calls and SMS is completely missing at this point. Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
-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