diff options
-rw-r--r-- | Android.mk | 32 | ||||
-rw-r--r-- | call.c | 40 | ||||
-rw-r--r-- | data.c | 605 | ||||
-rw-r--r-- | include/plmn_list.h | 2603 | ||||
-rwxr-xr-x | include/plmn_list.sh | 88 | ||||
-rw-r--r-- | include/sim.h | 51 | ||||
-rw-r--r-- | misc.c | 289 | ||||
-rw-r--r-- | network.c | 664 | ||||
-rw-r--r-- | power.c | 147 | ||||
-rw-r--r-- | qmi-client.c | 347 | ||||
-rw-r--r-- | qmi-ril.c | 1161 | ||||
-rw-r--r-- | qmi-ril.h | 253 | ||||
-rw-r--r-- | sim.c | 695 | ||||
-rw-r--r-- | utils.c | 144 | ||||
-rw-r--r-- | utils.h | 40 |
15 files changed, 7159 insertions, 0 deletions
@@ -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 @@ -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; +} @@ -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 MHz Public Safety Broadband", "700 MHz Public Safety Broadband" }, + { 313, 101, "700 MHz Public Safety Broadband", "700 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/\&/\&/g" -e "s/\<[^\&]*\>//g" -e "s/"//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 @@ -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, ®istration_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(®istration[0], "%d", ril_status_voice); + asprintf(®istration[1], "%x", lac); + asprintf(®istration[2], "%x", cid); + asprintf(®istration[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(®istration[0], "%d", ril_status_data); + asprintf(®istration[1], "%x", lac); + asprintf(®istration[2], "%x", cid); + asprintf(®istration[3], "%d", ril_technology); + /* + * number of simultanious data connections + * TODO: make it possible to setup more using multiple + * devices + */ + asprintf(®istration[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; +} @@ -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 @@ -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; +} @@ -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; +} @@ -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 |