diff options
-rw-r--r-- | Android.mk | 44 | ||||
-rw-r--r-- | call.c | 683 | ||||
-rw-r--r-- | client.c | 243 | ||||
-rw-r--r-- | data.c | 1049 | ||||
-rw-r--r-- | disp.c | 160 | ||||
-rw-r--r-- | gen.c | 275 | ||||
-rw-r--r-- | gprs.c | 1075 | ||||
-rw-r--r-- | include/plmn_list.h | 611 | ||||
-rwxr-xr-x | include/plmn_list.sh | 31 | ||||
-rw-r--r-- | include/ril_oem.h | 52 | ||||
-rw-r--r-- | include/samsung-ril-socket.h | 84 | ||||
-rw-r--r-- | include/sim.h | 60 | ||||
-rw-r--r-- | ipc.c | 1106 | ||||
-rw-r--r-- | ipc.h | 110 | ||||
-rw-r--r-- | misc.c | 362 | ||||
-rw-r--r-- | net.c | 916 | ||||
-rw-r--r-- | network.c | 1168 | ||||
-rw-r--r-- | oem.c | 238 | ||||
-rw-r--r-- | power.c | 117 | ||||
-rw-r--r-- | pwr.c | 110 | ||||
-rw-r--r-- | rfs.c | 148 | ||||
-rw-r--r-- | samsung-ril.c | 1812 | ||||
-rw-r--r-- | samsung-ril.h | 716 | ||||
-rw-r--r-- | sat.c | 166 | ||||
-rw-r--r-- | sec.c | 981 | ||||
-rw-r--r-- | sim.c | 1303 | ||||
-rw-r--r-- | sms.c | 1041 | ||||
-rw-r--r-- | snd.c | 132 | ||||
-rw-r--r-- | sound.c | 159 | ||||
-rw-r--r-- | srs-client/include/srs-client.h | 47 | ||||
-rw-r--r-- | srs-client/srs-client.c | 551 | ||||
-rw-r--r-- | srs.c | 1181 | ||||
-rw-r--r-- | srs.h | 95 | ||||
-rw-r--r-- | ss.c | 251 | ||||
-rw-r--r-- | svc.c | 244 | ||||
-rw-r--r-- | util.c | 486 | ||||
-rw-r--r-- | utils.c | 247 | ||||
-rw-r--r-- | utils.h (renamed from util.h) | 36 |
38 files changed, 10318 insertions, 7772 deletions
@@ -1,7 +1,7 @@ # This file is part of Samsung-RIL. # # Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> -# Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> +# Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> # # Samsung-RIL is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,38 +25,32 @@ LOCAL_SRC_FILES := \ client.c \ ipc.c \ srs.c \ - util.c \ - gen.c \ - pwr.c \ - disp.c \ - misc.c \ - sat.c \ - ss.c \ - sec.c \ - svc.c \ - net.c \ - sms.c \ + utils.c \ + power.c \ call.c \ - snd.c \ - gprs.c \ - rfs.c + sms.c \ + sim.c \ + network.c \ + sound.c \ + misc.c \ + oem.c \ + data.c \ + rfs.c \ + gen.c LOCAL_C_INCLUDES := \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/include \ external/libsamsung-ipc/include \ - $(LOCAL_PATH)/include + hardware/libhardware_legacy/include \ + system/core/include -LOCAL_CFLAGS := -D_GNU_SOURCE -DRIL_SHLIB +LOCAL_CFLAGS := -DRIL_SHLIB -# Disable STK -LOCAL_CFLAGS += -DDISABLE_STK - -# Samsung-RIL only supports IPC V4 -LOCAL_CFLAGS += -DDEVICE_IPC_V4 - -LOCAL_SHARED_LIBRARIES := libcutils libnetutils libutils liblog +LOCAL_SHARED_LIBRARIES := libcutils libnetutils libutils liblog libpower LOCAL_STATIC_LIBRARIES := libsamsung-ipc -LOCAL_PRELINK_MODULE := false +LOCAL_PRELINK_MODULE := false LOCAL_MODULE_TAGS := optional LOCAL_MODULE := libsamsung-ril @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,10 +18,12 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ -#define LOG_TAG "RIL-CALL" +#include <stdlib.h> + +#define LOG_TAG "RIL" #include <utils/Log.h> -#include "samsung-ril.h" +#include <samsung-ril.h> unsigned char ril2ipc_call_identity(int clir) { @@ -33,28 +35,26 @@ unsigned char ril2ipc_call_identity(int clir) case 2: return IPC_CALL_IDENTITY_HIDE; default: - RIL_LOGE("Unknown call identity: 0x%x", clir); return IPC_CALL_IDENTITY_DEFAULT; } } -unsigned char ipc2ril_call_list_entry_state(unsigned char call_state) +unsigned char ipc2ril_call_list_entry_state(unsigned char status) { - switch (call_state) { - case IPC_CALL_LIST_ENTRY_STATE_ACTIVE: + switch (status) { + case IPC_CALL_LIST_ENTRY_STATUS_ACTIVE: return RIL_CALL_ACTIVE; - case IPC_CALL_LIST_ENTRY_STATE_HOLDING: + case IPC_CALL_LIST_ENTRY_STATUS_HOLDING: return RIL_CALL_HOLDING; - case IPC_CALL_LIST_ENTRY_STATE_DIALING: + case IPC_CALL_LIST_ENTRY_STATUS_DIALING: return RIL_CALL_DIALING; - case IPC_CALL_LIST_ENTRY_STATE_ALERTING: + case IPC_CALL_LIST_ENTRY_STATUS_ALERTING: return RIL_CALL_ALERTING; - case IPC_CALL_LIST_ENTRY_STATE_INCOMING: + case IPC_CALL_LIST_ENTRY_STATUS_INCOMING: return RIL_CALL_INCOMING; - case IPC_CALL_LIST_ENTRY_STATE_WAITING: + case IPC_CALL_LIST_ENTRY_STATUS_WAITING: return RIL_CALL_WAITING; default: - RIL_LOGE("Unknown call list entry state: 0x%x", call_state); return -1; } } @@ -67,303 +67,618 @@ RIL_LastCallFailCause ipc2ril_call_fail_cause(unsigned char end_cause) return CALL_FAIL_NORMAL; case IPC_CALL_END_CAUSE_UNSPECIFIED: default: - RIL_LOGE("Unknown call fail cause: 0x%x", end_cause); return CALL_FAIL_ERROR_UNSPECIFIED; } } -void ipc_call_incoming(struct ipc_message_info *info) +int ril_request_dial(void *data, size_t size, RIL_Token token) +{ + struct ipc_call_outgoing_data request_data; + RIL_Dial *dial = NULL; + unsigned char identity; + unsigned char prefix; + int rc; + + if (data == NULL || size < sizeof(RIL_Dial)) + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + dial = (RIL_Dial *) data; + + if (dial->address == NULL) + goto error; + + identity = ril2ipc_call_identity(dial->clir); + prefix = dial->address[0] == '+' ? IPC_CALL_PREFIX_INTL : IPC_CALL_PREFIX_NONE; + + rc = ipc_call_outgoing_setup(&request_data, IPC_CALL_TYPE_VOICE, identity, prefix, dial->address); + if (rc < 0) + goto error; + + free(dial->address); + dial = NULL; + + rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_CALL_OUTGOING); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_OUTGOING, IPC_TYPE_EXEC, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (dial != NULL && dial->address != NULL) + free(dial->address); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_call_incoming(struct ipc_message *message) { ril_request_unsolicited(RIL_UNSOL_CALL_RING, NULL, 0); ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + + return 0; } -void ipc_call_status(struct ipc_message_info *info) +int ril_request_hangup(void *data, size_t size, RIL_Token token) { - struct ipc_call_status *call_status; + int hangup; + int rc; - if (info->data == NULL || info->length < sizeof(struct ipc_call_status)) - return; + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - call_status = (struct ipc_call_status *) info->data; + hangup = 1; + ril_request_data_set_uniq(RIL_REQUEST_HANGUP, &hangup, sizeof(hangup)); - RIL_LOGD("Updating call status data"); - memcpy(&(ril_data.state.call_status), call_status, sizeof(struct ipc_call_status)); + rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_CALL_RELEASE); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_RELEASE, IPC_TYPE_EXEC, NULL, 0); + if (rc < 0) + goto error; ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + ril_request_data_free(RIL_REQUEST_HANGUP); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; } -void ril_request_dial(RIL_Token t, void *data, size_t length) +int ril_request_answer(void *data, size_t size, RIL_Token token) { - RIL_Dial *dial; - struct ipc_call_outgoing call; - int clir; + int rc; - if (data == NULL || length < sizeof(RIL_Dial)) - goto error; + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - dial = (RIL_Dial *) data; + rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_CALL_ANSWER); + if (rc < 0) + goto error; - if (strlen(dial->address) > sizeof(call.number)) { - printf("Outgoing call number too long\n"); + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_ANSWER, IPC_TYPE_EXEC, NULL, 0); + if (rc < 0) goto error; - } - memset(&call, 0, sizeof(call)); - call.type = IPC_CALL_TYPE_VOICE; - call.identity = ril2ipc_call_identity(dial->clir); - call.prefix = dial->address[0] == '+' ? IPC_CALL_PREFIX_INTL : IPC_CALL_PREFIX_NONE; - call.length = strlen(dial->address); - memcpy(call.number, dial->address, strlen(dial->address)); + ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_OUTGOING); + rc = RIL_REQUEST_HANDLED; + goto complete; - ipc_fmt_send(IPC_CALL_OUTGOING, IPC_TYPE_EXEC, (unsigned char *) &call, sizeof(call), ril_request_get_id(t)); +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); - return; + rc = RIL_REQUEST_COMPLETED; -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); +complete: + return rc; +} + +int ipc_call_status(struct ipc_message *message) +{ + struct ipc_call_status_data *data; + int fail_cause; + void *hangup_data; + size_t hangup_size; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_call_status_data)) + return -1; + + data = (struct ipc_call_status_data *) message->data; + + // Nobody will ask for a call fail cause when we hangup ourselves + hangup_size = ril_request_data_size_get(RIL_REQUEST_HANGUP); + hangup_data = ril_request_data_get(RIL_REQUEST_HANGUP); + + if (data->status == IPC_CALL_STATUS_RELEASED && (hangup_data == NULL || hangup_size == 0)) { + fail_cause = ipc2ril_call_fail_cause(data->end_cause); + + ril_request_data_set_uniq(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, &fail_cause, sizeof(fail_cause)); + } else if (hangup_data != NULL && hangup_size > 0) { + free(hangup_data); + } + + ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + + return 0; } -void ril_request_get_current_calls(RIL_Token t) +int ril_request_last_call_fail_cause(void *data, size_t size, RIL_Token token) { - ipc_fmt_send_get(IPC_CALL_LIST, ril_request_get_id(t)); + void *fail_cause_data; + size_t fail_cause_size; + int fail_cause; + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + fail_cause_size = ril_request_data_size_get(RIL_REQUEST_LAST_CALL_FAIL_CAUSE); + fail_cause_data = ril_request_data_get(RIL_REQUEST_LAST_CALL_FAIL_CAUSE); + + if (fail_cause_data == NULL || fail_cause_size < sizeof(fail_cause)) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + fail_cause = *((int *) fail_cause_data); + + ril_request_complete(token, RIL_E_SUCCESS, &fail_cause, sizeof(fail_cause)); + + free(fail_cause_data); + + return RIL_REQUEST_COMPLETED; } -void ipc_call_list(struct ipc_message_info *info) +int ipc_call_list(struct ipc_message *message) { struct ipc_call_list_entry *entry; + RIL_Call **calls = NULL; + size_t calls_size; + unsigned int calls_count = 0; unsigned char count; + unsigned char index; char *number; - RIL_Call **current_calls = NULL; - int i; + int rc; - if (info->data == NULL || info->length < sizeof(unsigned char)) - goto error; + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_call_list_header)) + return -1; - if (info->type != IPC_TYPE_RESP) - return; + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; - count = *((unsigned char *) info->data); + count = ipc_call_list_count_extract(message->data, message->size); if (count == 0) { - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, NULL, 0); - return; + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); + return 0; } - current_calls = (RIL_Call **) calloc(1, count * sizeof(RIL_Call *)); - entry = (struct ipc_call_list_entry *) ((char *) info->data + sizeof(unsigned char)); + calls_size = count * sizeof(RIL_Call *); + calls = (RIL_Call **) calloc(1, calls_size); + + for (index = 0; index < count; index++) { + entry = ipc_call_list_entry_extract(message->data, message->size, index); + if (entry == NULL) + goto error; - for (i = 0 ; i < count ; i++) { - if (((int) entry - (int) info->data) >= (int) info->length) + number = ipc_call_list_entry_number_extract(entry); + if (number == NULL) goto error; - number = ((char *) entry) + sizeof(struct ipc_call_list_entry); - - current_calls[i] = (RIL_Call *) calloc(1, sizeof(RIL_Call)); - - current_calls[i]->state = ipc2ril_call_list_entry_state(entry->state); - current_calls[i]->index = entry->idx; - current_calls[i]->toa = (entry->number_len > 0 && number[0] == '+') ? 145 : 129; - current_calls[i]->isMpty = entry->mpty; - current_calls[i]->isMT = (entry->term == IPC_CALL_TERM_MT); - current_calls[i]->als = 0; - current_calls[i]->isVoice = (entry->type == IPC_CALL_TYPE_VOICE); - current_calls[i]->isVoicePrivacy = 0; - current_calls[i]->number = strdup(number); - current_calls[i]->numberPresentation = (entry->number_len > 0) ? 0 : 2; - current_calls[i]->name = NULL; - current_calls[i]->namePresentation = 2; - current_calls[i]->uusInfo = NULL; - - entry = (struct ipc_call_list_entry *) (number + entry->number_len); + calls[index] = (RIL_Call *) calloc(1, sizeof(RIL_Call)); + calls[index]->state = ipc2ril_call_list_entry_state(entry->status); + calls[index]->index = entry->id; + calls[index]->isMpty = entry->mpty; + calls[index]->isMT = entry->term == IPC_CALL_TERM_MT; + calls[index]->als = 0; + calls[index]->isVoice = entry->type == IPC_CALL_TYPE_VOICE; + calls[index]->isVoicePrivacy = 0; + calls[index]->number = strdup(number); + calls[index]->numberPresentation = (entry->number_length > 0) ? 0 : 2; + calls[index]->name = NULL; + calls[index]->namePresentation = 2; + calls[index]->uusInfo = NULL; + + if (entry->number_length > 0 && number != NULL && number[0] == '+') + calls[index]->toa = 145; + else + calls[index]->toa = 129; + + calls_count++; } - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, current_calls, (count * sizeof(RIL_Call *))); + calls_size = calls_count * sizeof(RIL_Call *); - for (i = 0 ; i < count ; i++) { - if (current_calls[i]->number != NULL) - free(current_calls[i]->number); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) calls, calls_size); - free(current_calls[i]); - } + goto complete; - free(current_calls); +error: + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - return; +complete: + if (calls != NULL && calls_size > 0) { + for (index = 0; index < calls_count; index++) { + if (calls[index] == NULL) + continue; -error: - if (current_calls != NULL) { - for (i = 0 ; i < count ; i++) { - if (current_calls[i]->number != NULL) - free(current_calls[i]->number); + if (calls[index]->number != NULL) + free(calls[index]->number); - free(current_calls[i]); + free(calls[index]); } - free(current_calls); + free(calls); } - if (info->type == IPC_TYPE_RESP) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return 0; } -void ril_request_hangup(RIL_Token t) +int ril_request_get_current_calls(void *data, size_t size, RIL_Token token) { - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_RELEASE); + 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; + } - ipc_fmt_send_exec(IPC_CALL_RELEASE, ril_request_get_id(t)); + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_LIST, IPC_TYPE_GET, NULL, 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } - ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + return RIL_REQUEST_HANDLED; } - -void ril_request_answer(RIL_Token t) +int ipc_call_cont_dtmf_callback(struct ipc_message *message) { - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_ANSWER); + struct ipc_gen_phone_res_data *data; + void *dtmf_data; + size_t dtmf_size; + char tone; + int rc; - ipc_fmt_send_exec(IPC_CALL_ANSWER, ril_request_get_id(t)); + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; - ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + data = (struct ipc_gen_phone_res_data *) message->data; + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) + goto error; + + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF_START); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF_START); + + if (dtmf_data != NULL && dtmf_size >= sizeof(tone)) { + tone = *((char *) dtmf_data); + + // Register a new DTMF tone + ril_request_data_set(RIL_REQUEST_DTMF_START, dtmf_data, dtmf_size); + + free(dtmf_data); + + rc = ril_request_dtmf_start_complete(message->aseq, tone); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_DTMF_START); + goto error; + } + } + + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF); + + if (dtmf_data != NULL && dtmf_size >= sizeof(tone)) { + tone = *((char *) dtmf_data); + + free(dtmf_data); + + rc = ril_request_dtmf_complete(message->aseq, tone); + if (rc < 0) + goto error; + } + + goto complete; + +error: + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + +complete: + return 0; } -void ril_request_last_call_fail_cause(RIL_Token t) +int ipc_call_burst_dtmf(struct ipc_message *message) { - RIL_LastCallFailCause fail_cause; - struct ipc_call_status *call_status = &(ril_data.state.call_status); + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_call_burst_dtmf_response_data)) + return -1; - fail_cause = ipc2ril_call_fail_cause(call_status->end_cause); + if (!ipc_seq_valid(message->aseq)) + return 0; - // Empty global call_status - memset(call_status, 0, sizeof(struct ipc_call_status)); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); - ril_request_complete(t, RIL_E_SUCCESS, &fail_cause, sizeof(RIL_LastCallFailCause)); + return 0; } -void ril_request_dtmf(RIL_Token t, void *data, int length) +int ril_request_dtmf_complete(unsigned char aseq, char tone) { - struct ipc_call_cont_dtmf cont_dtmf; - unsigned char tone; - unsigned char count; + struct ipc_call_burst_dtmf_request_entry entry; + void *request_data = NULL; + size_t request_size = 0; + int rc; - unsigned char *burst; - int burst_length; + memset(&entry, 0, sizeof(entry)); + entry.status = IPC_CALL_DTMF_STATUS_START; + entry.tone = tone; - int i; + request_size = ipc_call_burst_dtmf_size_setup(&entry, 1); + if (request_size == 0) + goto error; - if (data == NULL || length < (int) sizeof(unsigned char)) + request_data = ipc_call_burst_dtmf_setup(&entry, 1); + if (request_data == NULL) goto error; - tone = *((unsigned char *) data); - count = 1; + rc = ipc_gen_phone_res_expect_abort(aseq, IPC_CALL_BURST_DTMF); + if (rc < 0) + goto error; - if (ril_data.state.dtmf_tone != 0) { - RIL_LOGD("Another tone wasn't stopped, stopping it before anything"); + rc = ipc_fmt_send(aseq, IPC_CALL_BURST_DTMF, IPC_TYPE_EXEC, request_data, request_size); + if (rc < 0) + goto error; - cont_dtmf.state = IPC_CALL_DTMF_STATE_STOP; - cont_dtmf.tone = 0; + rc = 0; + goto complete; - ipc_fmt_send(IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (void *) &cont_dtmf, sizeof(cont_dtmf), ril_request_get_id(t)); +error: + rc = -1; - usleep(300); - } +complete: + if (request_data != NULL && request_size > 0) + free(request_data); - burst_length = sizeof(struct ipc_call_cont_dtmf) * count + 1; - burst = calloc(1, burst_length); + return rc; +} - burst[0] = count; +int ril_request_dtmf(void *data, size_t size, RIL_Token token) +{ + struct ril_request *request; + void *dtmf_data; + size_t dtmf_size; + char tone; + int rc; - // Apparently, it's possible to set multiple DTMF tones on this message - for (i = 0 ; i < count ; i++) { - cont_dtmf.state = IPC_CALL_DTMF_STATE_START; - cont_dtmf.tone = tone; + if (data == NULL || size < sizeof(char)) + goto error; - memcpy(burst + 1 + sizeof(struct ipc_call_cont_dtmf) * i, &cont_dtmf, sizeof(cont_dtmf)); - } + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - ipc_gen_phone_res_expect_to_abort(ril_request_get_id(t), IPC_CALL_BURST_DTMF); + request = ril_request_find_request_status(RIL_REQUEST_DTMF, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - ipc_fmt_send(IPC_CALL_BURST_DTMF, IPC_TYPE_EXEC, burst, burst_length, ril_request_get_id(t)); + request = ril_request_find_request_status(RIL_REQUEST_DTMF_START, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - free(burst); + request = ril_request_find_request_status(RIL_REQUEST_DTMF_STOP, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - return; + tone = *((char *) data); -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} + // A previous DTMF tone was started + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF_START); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF_START); -void ipc_call_burst_dtmf(struct ipc_message_info *info) -{ - unsigned char code; + if (dtmf_data != NULL && dtmf_size >= sizeof(tone)) { + free(dtmf_data); - if (info->data == NULL || info->length < sizeof(unsigned char)) - goto error; + // Let the callback know what to do after completing the previous DTMF tone + ril_request_data_set(RIL_REQUEST_DTMF, data, size); - code = *((unsigned char *) info->data); + rc = ril_request_dtmf_stop_complete(ipc_fmt_request_seq(token), 1); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_DTMF); + goto error; + } - // This apparently should return 1, or perhaps that is the DTMF tones count - if (code == 0) { - RIL_LOGD("Apparently, something went wrong with DTMF burst (code=0x%x)", code); - goto error; + rc = RIL_REQUEST_HANDLED; + goto complete; } - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, NULL, 0); + rc = ril_request_dtmf_complete(ipc_fmt_request_seq(token), tone); + if (rc < 0) + goto error; - return; + rc = RIL_REQUEST_HANDLED; + goto complete; error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_dtmf_start_complete(unsigned char aseq, char tone) +{ + struct ipc_call_cont_dtmf_data request_data; + int rc; + + memset(&request_data, 0, sizeof(request_data)); + request_data.status = IPC_CALL_DTMF_STATUS_START; + request_data.tone = tone; + + rc = ipc_gen_phone_res_expect_complete(aseq, IPC_CALL_CONT_DTMF); + if (rc < 0) + return -1; + + rc = ipc_fmt_send(aseq, IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + return -1; + + return 0; } -void ril_request_dtmf_start(RIL_Token t, void *data, int length) +int ril_request_dtmf_start(void *data, size_t size, RIL_Token token) { - struct ipc_call_cont_dtmf cont_dtmf; - unsigned char tone; + struct ril_request *request; + void *dtmf_data; + size_t dtmf_size; + char tone; + int rc; - if (data == NULL || length < (int) sizeof(unsigned char)) + if (data == NULL || size < sizeof(char)) goto error; - tone = *((unsigned char *) data); + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - if (ril_data.state.dtmf_tone != 0) { - RIL_LOGD("Another tone wasn't stopped, stopping it before anything"); + request = ril_request_find_request_status(RIL_REQUEST_DTMF, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - cont_dtmf.state = IPC_CALL_DTMF_STATE_STOP; - cont_dtmf.tone = 0; + request = ril_request_find_request_status(RIL_REQUEST_DTMF_START, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - ipc_fmt_send(IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (unsigned char *) &cont_dtmf, sizeof(cont_dtmf), ril_request_get_id(t)); + request = ril_request_find_request_status(RIL_REQUEST_DTMF_STOP, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - usleep(300); - } + tone = *((char *) data); - ril_data.state.dtmf_tone = cont_dtmf.tone; + // A previous DTMF tone was started + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF_START); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF_START); - cont_dtmf.state = IPC_CALL_DTMF_STATE_START; - cont_dtmf.tone = tone; + if (dtmf_data != NULL && dtmf_size >= sizeof(tone)) { + free(dtmf_data); - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_CONT_DTMF); + // Let the callback know what to do after completing the previous DTMF tone + ril_request_data_set(RIL_REQUEST_DTMF_START, data, size); - ipc_fmt_send(IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (unsigned char *) &cont_dtmf, sizeof(cont_dtmf), ril_request_get_id(t)); + rc = ril_request_dtmf_stop_complete(ipc_fmt_request_seq(token), 1); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_DTMF_START); + goto error; + } + + rc = RIL_REQUEST_HANDLED; + goto complete; + } + + // Register a new DTMF tone + ril_request_data_set(RIL_REQUEST_DTMF_START, data, size); + + rc = ril_request_dtmf_start_complete(ipc_fmt_request_seq(token), tone); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_DTMF_START); + goto error; + } - return; + rc = RIL_REQUEST_HANDLED; + goto complete; error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; } -void ril_request_dtmf_stop(RIL_Token t) +int ril_request_dtmf_stop_complete(unsigned char aseq, int callback) { - struct ipc_call_cont_dtmf cont_dtmf; + struct ipc_call_cont_dtmf_data request_data; + int rc; + + memset(&request_data, 0, sizeof(request_data)); + request_data.status = IPC_CALL_DTMF_STATUS_STOP; + request_data.tone = 0; + + if (callback) + rc = ipc_gen_phone_res_expect_callback(aseq, IPC_CALL_CONT_DTMF, ipc_call_cont_dtmf_callback); + else + rc = ipc_gen_phone_res_expect_complete(aseq, IPC_CALL_CONT_DTMF); - ril_data.state.dtmf_tone = 0; + if (rc < 0) + return -1; - cont_dtmf.state = IPC_CALL_DTMF_STATE_STOP; - cont_dtmf.tone = 0; + rc = ipc_fmt_send(aseq, IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + return -1; - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_CONT_DTMF); + return 0; +} + +int ril_request_dtmf_stop(void *data, size_t size, RIL_Token token) +{ + struct ril_request *request; + void *dtmf_data; + size_t dtmf_size; + int rc; + + request = ril_request_find_request_status(RIL_REQUEST_DTMF, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_DTMF_START, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_DTMF_STOP, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + // Clear the DTMF tone + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF_START); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF_START); + + if (dtmf_data != NULL && dtmf_size >= sizeof(char)) + free(dtmf_data); + + rc = ril_request_dtmf_stop_complete(ipc_fmt_request_seq(token), 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } - ipc_fmt_send(IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (unsigned char *) &cont_dtmf, sizeof(cont_dtmf), ril_request_get_id(t)); + return RIL_REQUEST_HANDLED; } @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,101 +17,115 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdlib.h> #include <pthread.h> #define LOG_TAG "RIL" #include <utils/Log.h> -#include "samsung-ril.h" +#include <samsung-ril.h> -struct ril_client *ril_client_new(struct ril_client_funcs *client_funcs) +struct ril_client *ril_client_find_id(int id) { - struct ril_client *ril_client; - int rc; + unsigned int i; - ril_client = calloc(1, sizeof(struct ril_client)); + if (ril_clients == NULL || ril_clients_count == 0) + return NULL; - if (client_funcs != NULL) { - ril_client->funcs.create = client_funcs->create; - ril_client->funcs.destroy = client_funcs->destroy; - ril_client->funcs.read_loop = client_funcs->read_loop; - } + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; - pthread_mutex_init(&(ril_client->mutex), NULL); + if (ril_clients[i]->id == id) + return ril_clients[i]; + } - return ril_client; + return NULL; } -int ril_client_free(struct ril_client *client) +int ril_client_create(struct ril_client *client) { + int rc; + if (client == NULL) return -1; - pthread_mutex_destroy(&(client->mutex)); + client->data = NULL; + pthread_mutex_init(&client->mutex, NULL); + + if (client->handlers != NULL && client->handlers->create != NULL) { + rc = client->handlers->create(client); + if (rc < 0) { + RIL_LOGE("Creating %s client failed", client->name); + return -1; + } + } - free(client); + RIL_LOGD("Created %s client", client->name); return 0; } -int ril_client_create(struct ril_client *client) +int ril_client_destroy(struct ril_client *client) { int rc; - int c; - if (client == NULL || client->funcs.create == NULL) + if (client == NULL) return -1; - for (c = RIL_CLIENT_MAX_TRIES ; c > 0 ; c--) { - RIL_LOGD("Creating RIL client inners, try #%d", RIL_CLIENT_MAX_TRIES - c + 1); + if (client->handlers != NULL && client->handlers->destroy != NULL) { + rc = client->handlers->destroy(client); + if (rc < 0) { + RIL_LOGE("Destroying %s client failed", client->name); + return -1; + } + } - rc = client->funcs.create(client); - if (rc < 0) - RIL_LOGE("RIL client inners creation failed"); - else - break; + pthread_mutex_destroy(&client->mutex); - usleep(500000); - } + RIL_LOGD("Destroyed %s client", client->name); + + return 0; +} - if (c == 0) { - RIL_LOGE("RIL client inners creation failed too many times"); - client->state = RIL_CLIENT_ERROR; +int ril_client_open(struct ril_client *client) +{ + int rc = 0; + + if (client == NULL) + return -1; + + if (client->handlers == NULL || client->handlers->open == NULL) + return -1; + + rc = client->handlers->open(client); + if (rc < 0) { + RIL_LOGE("Opening %s client failed", client->name); return -1; } - client->state = RIL_CLIENT_CREATED; + RIL_LOGD("Opened %s client", client->name); return 0; } -int ril_client_destroy(struct ril_client *client) +int ril_client_close(struct ril_client *client) { int rc; - int c; - if (client == NULL || client->funcs.destroy == NULL) + if (client == NULL) return -1; - for (c = RIL_CLIENT_MAX_TRIES ; c > 0 ; c--) { - RIL_LOGD("Destroying RIL client inners, try #%d", RIL_CLIENT_MAX_TRIES - c + 1); - - rc = client->funcs.destroy(client); - if (rc < 0) - RIL_LOGE("RIL client inners destroying failed"); - else - break; - - usleep(500000); - } + if (client->handlers == NULL || client->handlers->close == NULL) + return -1; - if (c == 0) { - RIL_LOGE("RIL client inners destroying failed too many times"); - client->state = RIL_CLIENT_ERROR; + rc = client->handlers->close(client); + if (rc < 0) { + RIL_LOGE("Closing %s client failed", client->name); return -1; } - client->state = RIL_CLIENT_DESTROYED; + RIL_LOGD("Closed %s client", client->name); return 0; } @@ -120,69 +134,130 @@ void *ril_client_thread(void *data) { struct ril_client *client; int rc; - int c; - if (data == NULL) + if (data == NULL || ril_data == NULL) return NULL; client = (struct ril_client *) data; - if (client->funcs.read_loop == NULL) - return NULL; + client->failures = 0; - for (c = RIL_CLIENT_MAX_TRIES ; c > 0 ; c--) { - client->state = RIL_CLIENT_READY; + do { + if (client->failures) { + usleep(RIL_CLIENT_RETRY_DELAY); - rc = client->funcs.read_loop(client); - if (rc < 0) { - client->state = RIL_CLIENT_ERROR; + rc = ril_client_close(client); + if (rc < 0) + goto failure; - RIL_LOGE("RIL client read loop failed"); + if (client->failures > 1) { + rc = ril_client_destroy(client); + if (rc < 0) + goto failure; - ril_client_destroy(client); - ril_client_create(client); + rc = ril_client_create(client); + if (rc < 0) + goto failure; + } - continue; - } else { - client->state = RIL_CLIENT_CREATED; + rc = ril_client_open(client); + if (rc < 0) + goto failure; + } + + rc = client->handlers->loop(client); + if (rc < 0) { + RIL_LOGE("%s client loop failed", client->name); + + if (client->critical) { + RIL_LOCK(); + ril_radio_state_update(RADIO_STATE_UNAVAILABLE); + RIL_UNLOCK(); + } - RIL_LOGD("RIL client read loop ended"); + goto failure; + } else { + RIL_LOGE("%s client loop terminated", client->name); break; } - } - - if (c == 0) { - RIL_LOGE("RIL client read loop failed too many times"); - client->state = RIL_CLIENT_ERROR; - } - // Destroy everything here +failure: + client->failures++; + } while (client->failures < RIL_CLIENT_RETRY_COUNT); - rc = ril_client_destroy(client); - if (rc < 0) - RIL_LOGE("RIL client destroy failed"); + ril_client_close(client); + ril_client_destroy(client); - rc = ril_client_free(client); - if (rc < 0) - RIL_LOGE("RIL client free failed"); + RIL_LOGD("Stopped %s client loop", client->name); - return 0; + return NULL; } -int ril_client_thread_start(struct ril_client *client) +int ril_client_loop(struct ril_client *client) { pthread_attr_t attr; int rc; + if (client == NULL) + return -1; + + if (client->handlers == NULL || client->handlers->loop == NULL) + return -1; + pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - rc = pthread_create(&(client->thread), &attr, ril_client_thread, (void *) client); - + rc = pthread_create(&client->thread, &attr, ril_client_thread, (void *) client); if (rc != 0) { - RIL_LOGE("RIL client thread creation failed"); + RIL_LOGE("Starting %s client loop failed", client->name); return -1; } + RIL_LOGD("Started %s client loop", client->name); + + return 0; +} + +int ril_client_request_register(struct ril_client *client, int request, + RIL_Token token) +{ + int rc = 0; + + if (client == NULL || client->callbacks == NULL || client->callbacks->request_register == NULL) + return -1; + + rc = client->callbacks->request_register(client, request, token); + if (rc < 0) + return -1; + + return 0; +} + +int ril_client_request_unregister(struct ril_client *client, int request, + RIL_Token token) +{ + int rc = 0; + + if (client == NULL || client->callbacks == NULL || client->callbacks->request_unregister == NULL) + return -1; + + rc = client->callbacks->request_unregister(client, request, token); + if (rc < 0) + return -1; + + return 0; +} + +int ril_client_flush(struct ril_client *client) +{ + int rc = 0; + + if (client == NULL || client->callbacks == NULL || client->callbacks->flush == NULL) + return -1; + + rc = client->callbacks->flush(client); + if (rc < 0) + return -1; + return 0; } @@ -0,0 +1,1049 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011 Denis 'GNUtoo' Carikli <GNUtoo@no-log.org> + * + * Samsung-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. + * + * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <arpa/inet.h> + +#define LOG_TAG "RIL" +#include <utils/Log.h> +#include <netutils/ifc.h> + +#include <samsung-ril.h> +#include <utils.h> + +int ipc2ril_gprs_fail_cause(unsigned char fail_cause) +{ + switch (fail_cause) { + case IPC_GPRS_FAIL_CAUSE_NONE: + case IPC_GPRS_FAIL_CAUSE_REL_BY_USER: + case IPC_GPRS_FAIL_CAUSE_REGULAR_DEACTIVATION: + return PDP_FAIL_NONE; + case IPC_GPRS_FAIL_CAUSE_INSUFFICIENT_RESOURCE: + return PDP_FAIL_INSUFFICIENT_RESOURCES; + case IPC_GPRS_FAIL_CAUSE_UNKNOWN_APN: + return PDP_FAIL_MISSING_UKNOWN_APN; + case IPC_GPRS_FAIL_CAUSE_UNKNOWN_PDP_ADDRESS: + return PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE; + case IPC_GPRS_FAIL_CAUSE_USER_AUTH_FAILED: + return PDP_FAIL_USER_AUTHENTICATION; + case IPC_GPRS_FAIL_CAUSE_ACT_REJ_GGSN: + return PDP_FAIL_ACTIVATION_REJECT_GGSN; + case IPC_GPRS_FAIL_CAUSE_ACT_REJ_UNSPECIFIED: + return PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED; + case IPC_GPRS_FAIL_CAUSE_SVC_OPTION_NOT_SUPPORTED: + return PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED; + case IPC_GPRS_FAIL_CAUSE_SVC_NOT_SUBSCRIBED: + return PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED; + case IPC_GPRS_FAIL_CAUSE_SVC_OPT_OUT_ORDER: + return PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER; + case IPC_GPRS_FAIL_CAUSE_NSAPI_USED: + return PDP_FAIL_NSAPI_IN_USE; + case IPC_GPRS_FAIL_CAUSE_NETWORK_FAILURE: + return PDP_FAIL_DATA_REGISTRATION_FAIL; + case IPC_GPRS_FAIL_CAUSE_UNKOWN_PDP_CONTEXT: + case IPC_GPRS_FAIL_CAUSE_INVALID_MSG: + case IPC_GPRS_FAIL_CAUSE_PROTOCOL_ERROR: + return PDP_FAIL_PROTOCOL_ERRORS; + case IPC_GPRS_FAIL_CAUSE_MOBILE_FAILURE_ERROR: + return PDP_FAIL_SIGNAL_LOST; + case IPC_GPRS_FAIL_CAUSE_UNKNOWN_ERROR: + default: + return PDP_FAIL_ERROR_UNSPECIFIED; + } +} + +int ril_data_connection_register(unsigned int cid, char *apn, char *username, + char *password, char *iface) +{ + struct ril_data_connection *data_connection; + struct list_head *list_end; + struct list_head *list; + unsigned int i; + + if (apn == NULL || ril_data == NULL) + return -1; + + data_connection = (struct ril_data_connection *) calloc(1, sizeof(struct ril_data_connection)); + data_connection->cid = cid; + data_connection->enabled = 0; + data_connection->apn = apn; + data_connection->username = username; + data_connection->password = password; + data_connection->iface = iface; + + list_end = ril_data->data_connections; + while (list_end != NULL && list_end->next != NULL) + list_end = list_end->next; + + list = list_head_alloc(list_end, NULL, (void *) data_connection); + + if (ril_data->data_connections == NULL) + ril_data->data_connections = list; + + return 0; +} + +int ril_data_connection_unregister(struct ril_data_connection *data_connection) +{ + struct list_head *list; + unsigned int i; + + if (data_connection == NULL || ril_data == NULL) + return -1; + + list = ril_data->data_connections; + while (list != NULL) { + if (list->data == (void *) data_connection) { + memset(data_connection, 0, sizeof(struct ril_data_connection)); + free(data_connection); + + if (list == ril_data->data_connections) + ril_data->data_connections = list->next; + + list_head_free(list); + + break; + } + +list_continue: + list = list->next; + } + + return 0; +} + +int ril_data_connection_flush(void) +{ + struct ril_data_connection *data_connection; + struct list_head *list; + struct list_head *list_next; + + if (ril_data == NULL) + return -1; + + list = ril_data->data_connections; + while (list != NULL) { + if (list->data != NULL) { + data_connection = (struct ril_data_connection *) list->data; + + ril_data_connection_stop(data_connection); + + memset(data_connection, 0, sizeof(struct ril_data_connection)); + free(data_connection); + } + + if (list == ril_data->data_connections) + ril_data->data_connections = list->next; + + list_next = list->next; + + list_head_free(list); + +list_continue: + list = list_next; + } + + return 0; +} + +struct ril_data_connection *ril_data_connection_find_cid(unsigned int cid) +{ + struct ril_data_connection *data_connection; + struct list_head *list; + + if (ril_data == NULL) + return NULL; + + list = ril_data->data_connections; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + data_connection = (struct ril_data_connection *) list->data; + + if (data_connection->cid == cid) + return data_connection; + +list_continue: + list = list->next; + } + + return NULL; +} + +struct ril_data_connection *ril_data_connection_find_token(RIL_Token token) +{ + struct ril_data_connection *data_connection; + struct list_head *list; + + if (ril_data == NULL) + return NULL; + + list = ril_data->data_connections; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + data_connection = (struct ril_data_connection *) list->data; + + if (data_connection->token == token) + return data_connection; + +list_continue: + list = list->next; + } + + return NULL; +} + +struct ril_data_connection *ril_data_connection_start(char *apn, char *username, + char *password) +{ + struct ril_data_connection *data_connection; + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + struct ipc_client_gprs_capabilities gprs_capabilities; + char *iface = NULL; + unsigned int cid; + unsigned int i; + int rc; + + if (apn == NULL) + goto error; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + goto error; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + if (ipc_fmt_data->ipc_client == NULL) + goto error; + + rc = ipc_client_gprs_get_capabilities(ipc_fmt_data->ipc_client, &gprs_capabilities); + if (rc < 0) + goto error; + + for (i = 0; i < gprs_capabilities.cid_count; i++) { + data_connection = ril_data_connection_find_cid(i + 1); + if (data_connection == NULL) + break; + } + + cid = i + 1; + + if (cid > gprs_capabilities.cid_count) { + RIL_LOGE("%s: No place left for a new data connection", __func__); + goto error; + } + + iface = ipc_client_gprs_get_iface(ipc_fmt_data->ipc_client, cid); + if (iface == NULL) + goto error; + + rc = ril_data_connection_register(cid, apn, username, password, iface); + if (rc < 0) + goto error; + + data_connection = ril_data_connection_find_cid(cid); + if (data_connection == NULL) + goto error; + + RIL_LOGD("Starting new data connection with cid: %d and iface: %s", cid, iface); + + goto complete; + +error: + if (iface != NULL) + free(iface); + + data_connection = NULL; + +complete: + return data_connection; +} + +int ril_data_connection_stop(struct ril_data_connection *data_connection) +{ + int rc; + + if (data_connection == NULL) + return -1; + + if (data_connection->apn != NULL) + free(data_connection->apn); + + if (data_connection->username != NULL) + free(data_connection->username); + + if (data_connection->password != NULL) + free(data_connection->password); + + if (data_connection->iface != NULL) + free(data_connection->iface); + + if (data_connection->ip != NULL) + free(data_connection->ip); + + if (data_connection->gateway != NULL) + free(data_connection->gateway); + + if (data_connection->subnet_mask != NULL) + free(data_connection->subnet_mask); + + if (data_connection->dns1 != NULL) + free(data_connection->dns1); + + if (data_connection->dns2 != NULL) + free(data_connection->dns2); + + rc = ril_data_connection_unregister(data_connection); + if (rc < 0) + return -1; + + return 0; +} + +int ril_data_connection_enable(struct ril_data_connection *data_connection) +{ + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + 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 == NULL || data_connection->gateway == NULL || data_connection->subnet_mask == NULL) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return -1; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + if (ipc_fmt_data->ipc_client == NULL) + return -1; + + rc = ipc_client_gprs_activate(ipc_fmt_data->ipc_client, data_connection->cid); + if (rc < 0) + return -1; + + ip_addr = inet_addr(data_connection->ip); + 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, ipv4NetmaskToPrefixLength(subnet_mask_addr), gateway_addr, dns1_addr, dns2_addr); + if (rc < 0) + return -1; + + data_connection->enabled = 1; + + RIL_LOGD("%s: Enabled data connection with cid %d", __func__, data_connection->cid); + + return 0; +} + +int ril_data_connection_disable(struct ril_data_connection *data_connection) +{ + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + int rc; + + if (data_connection == NULL || data_connection->iface == NULL) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return -1; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + if (ipc_fmt_data->ipc_client == NULL) + return -1; + + rc = ifc_reset_connections(data_connection->iface, RESET_IPV4_ADDRESSES); + if (rc < 0) + return -1; + + rc = ifc_disable(data_connection->iface); + if (rc < 0) + return -1; + + rc = ipc_client_gprs_deactivate(ipc_fmt_data->ipc_client, data_connection->cid); + if (rc < 0) + return -1; + + data_connection->enabled = 0; + + RIL_LOGD("%s: Disabled data connection with cid %d", __func__, data_connection->cid); + + return 0;; +} + +int ipc_gprs_define_pdp_context_callback(struct ipc_message *message) +{ + struct ipc_gprs_pdp_context_request_set_data request_data; + struct ril_data_connection *data_connection; + struct ipc_gen_phone_res_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; + + data = (struct ipc_gen_phone_res_data *) message->data; + + data_connection = ril_data_connection_find_token(ipc_fmt_request_token(message->aseq)); + if (data_connection == NULL) { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return 0; + } + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) + goto error; + + rc = ipc_gprs_pdp_context_request_set_setup(&request_data, 1, data_connection->cid, data_connection->username, data_connection->password); + if (rc < 0) + goto error; + + rc = ipc_gen_phone_res_expect_callback(message->aseq, IPC_GPRS_PDP_CONTEXT, ipc_gprs_pdp_context_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(message->aseq, IPC_GPRS_PDP_CONTEXT, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + goto complete; + +error: + ril_data_connection_stop(data_connection); + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + +complete: + return 0; +} + +int ril_request_setup_data_call(void *data, size_t size, RIL_Token token) +{ + struct ipc_gprs_define_pdp_context_data request_data; + struct ril_data_connection *data_connection = NULL; + struct ril_request *request; + char *apn = NULL; + char *username = NULL; + char *password = NULL; + char **values = NULL; + unsigned int i; + 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; + + values = (char **) data; + + if (values[2] == NULL) { + RIL_LOGE("%s: No APN was provided", __func__); + goto error; + } + + apn = strdup(values[2]); + + if (values[3] != NULL) + username = strdup(values[3]); + + if (values[4] != NULL) + password = strdup(values[4]); + + strings_array_free(values, size); + values = NULL; + + RIL_LOGD("Setting up data connection to APN: %s with username/password: %s/%s", apn, username, password); + + data_connection = ril_data_connection_start(apn, username, password); + if (data_connection == NULL) + goto error; + + data_connection->token = token; + + rc = ipc_gprs_define_pdp_context_setup(&request_data, 1, data_connection->cid, data_connection->apn); + if (rc < 0) + goto error; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_GPRS_DEFINE_PDP_CONTEXT, ipc_gprs_define_pdp_context_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + if (data_connection != NULL) { + ril_data_connection_stop(data_connection); + } else { + 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; +} + +int ipc_gprs_ps(struct ipc_message *message) +{ + struct ipc_gprs_ps_data *data; + struct ril_data_connection *data_connection; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gprs_ps_data)) + return -1; + + data = (struct ipc_gprs_ps_data *) message->data; + + data_connection = ril_data_connection_find_cid(data->cid); + if (data_connection == NULL) + return 0; + + data_connection->attached = !!data->attached; + + return 0; +} + +int ipc_gprs_pdp_context(struct ipc_message *message) +{ + struct ipc_gprs_pdp_context_request_get_data *data; + struct ril_data_connection *data_connection; +#if RIL_VERSION >= 6 + RIL_Data_Call_Response_v6 response[3]; +#else + RIL_Data_Call_Response response[3]; +#endif + unsigned int entries_count; + unsigned int index = 0; + size_t size; + unsigned int i; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gprs_pdp_context_request_get_data)) + return -1; + + data = (struct ipc_gprs_pdp_context_request_get_data *) message->data; + + entries_count = sizeof(data->entries) / sizeof(struct ipc_gprs_pdp_context_request_get_entry); + + memset(&response, 0, sizeof(response)); + + for (i = 0; i < entries_count; i++) { + if (!data->entries[i].active) + continue; + + data_connection = ril_data_connection_find_cid(data->entries[i].cid); + if (data_connection == NULL) + continue; + +#if RIL_VERSION >= 6 + response[index].status = PDP_FAIL_NONE; +#endif + response[index].cid = data->entries[i].cid; + + if (data_connection->enabled) + response[index].active = 2; + else + response[index].active = 0; + + response[index].type = strdup("IP"); +#if RIL_VERSION >= 6 + if (data_connection->iface != NULL) + response[index].ifname = strdup(data_connection->iface); + + if (data_connection->ip != NULL) + response[index].addresses = strdup(data_connection->ip); + + asprintf(&response[index].dnses, "%s %s", data_connection->dns1, data_connection->dns2); + + if (data_connection->gateway != NULL) + response[index].gateways = strdup(data_connection->gateway); +#else + if (data_connection->apn != NULL) + response[index].apn = strdup(data_connection->apn); + + if (data_connection->ip != NULL) + response[index].address = strdup(data_connection->ip); +#endif + + index++; + } + +#if RIL_VERSION >= 6 + size = index * sizeof(RIL_Data_Call_Response_v6); +#else + size = index * sizeof(RIL_Data_Call_Response); +#endif + + if (!ipc_seq_valid(message->aseq)) + ril_request_unsolicited(RIL_UNSOL_DATA_CALL_LIST_CHANGED, &response, size); + else + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &response, size); + + for (i = 0; i < index; i++) { + if (response[i].type != NULL) + free(response[i].type); + +#if RIL_VERSION >= 6 + if (response[i].ifname != NULL) + free(response[i].ifname); + + if (response[i].addresses != NULL) + free(response[i].addresses); + + if (response[i].dnses != NULL) + free(response[i].dnses); + + if (response[i].gateways != NULL) + free(response[i].gateways); +#else + if (response[i].apn != NULL) + free(response[i].apn); + + if (response[i].address != NULL) + free(response[i].address); +#endif + } + + return 0; +} + +int ril_request_data_call_list(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; + } + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_GPRS_PDP_CONTEXT, IPC_TYPE_GET, NULL, 0); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_gprs_pdp_context_callback(struct ipc_message *message) +{ + struct ril_data_connection *data_connection; + struct ipc_gen_phone_res_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; + + data = (struct ipc_gen_phone_res_data *) message->data; + + data_connection = ril_data_connection_find_token(ipc_fmt_request_token(message->aseq)); + if (data_connection == NULL) { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return 0; + } + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) + goto error; + + goto complete; + +error: + ril_data_connection_stop(data_connection); + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + +complete: + return 0; +} + +int ril_request_deactivate_data_call(void *data, size_t size, RIL_Token token) +{ + struct ipc_gprs_pdp_context_request_set_data request_data; + struct ril_data_connection *data_connection = NULL; + struct ril_request *request; + char **values = NULL; + unsigned int cid; + unsigned int i; + int rc; + + if (data == NULL || size < 2 * sizeof(char *)) + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_DEACTIVATE_DATA_CALL, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + if (values[0] == NULL) { + RIL_LOGE("%s: No cid was provided", __func__); + goto error; + } + + cid = (unsigned int) atoi(values[0]); + + strings_array_free(values, size); + values = NULL; + + data_connection = ril_data_connection_find_cid(cid); + if (data_connection == NULL) + goto error; + + data_connection->token = token; + + rc = ipc_gprs_pdp_context_request_set_setup(&request_data, 0, data_connection->cid, NULL, NULL); + if (rc < 0) + goto error; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_GPRS_PDP_CONTEXT, ipc_gprs_pdp_context_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_GPRS_PDP_CONTEXT, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + if (data_connection != NULL) + ril_data_connection_stop(data_connection); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_gprs_ip_configuration(struct ipc_message *message) +{ + struct ipc_gprs_ip_configuration_data *data; + struct ril_data_connection *data_connection; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gprs_ip_configuration_data)) + return -1; + + data = (struct ipc_gprs_ip_configuration_data *) message->data; + + data_connection = ril_data_connection_find_cid(data->cid); + if (data_connection == NULL) { + if (ipc_seq_valid(message->aseq)) + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + + return 0; + } + + if (data_connection->ip != NULL) + free(data_connection->ip); + + asprintf(&data_connection->ip, "%i.%i.%i.%i", data->ip[0], data->ip[1], data->ip[2], data->ip[3]); + + if (data_connection->gateway != NULL) + free(data_connection->gateway); + + asprintf(&data_connection->gateway, "%i.%i.%i.%i", data->ip[0], data->ip[1], data->ip[2], data->ip[3]); + + if (data_connection->subnet_mask != NULL) + free(data_connection->subnet_mask); + + asprintf(&data_connection->subnet_mask, "255.255.255.255"); + + if (data_connection->dns1 != NULL) + free(data_connection->dns1); + + asprintf(&data_connection->dns1, "%i.%i.%i.%i", data->dns1[0], data->dns1[1], data->dns1[2], data->dns1[3]); + + if (data_connection->dns2 != NULL) + free(data_connection->dns2); + + asprintf(&data_connection->dns2, "%i.%i.%i.%i", data->dns2[0], data->dns2[1], data->dns2[2], data->dns2[3]); + + return 0; +} + +int ipc_gprs_hsdpa_status(struct ipc_message *message) +{ + struct ipc_gprs_hsdpa_status_data *data; + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gprs_hsdpa_status_data)) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_gprs_hsdpa_status_data *) message->data; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + + if (ipc_fmt_data->hsdpa_status_data.status != data->status) { + ipc_fmt_data->hsdpa_status_data.status = data->status; + +#if RIL_VERSION >= 6 + ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); +#else + ril_request_unsolicited(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); +#endif + } + + return 0; +} + +int ipc_gprs_call_status(struct ipc_message *message) +{ +#if RIL_VERSION >= 6 + RIL_Data_Call_Response_v6 response; +#else + char *setup_data_call_response[3]; +#endif + struct ipc_gprs_call_status_data *data; + struct ril_data_connection *data_connection; + struct ril_request *request; + int fail_cause; + unsigned int i; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gprs_call_status_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return 0; + + data = (struct ipc_gprs_call_status_data *) message->data; + + data_connection = ril_data_connection_find_cid(data->cid); + if (data_connection == NULL) { + RIL_LOGE("%s: Finding data connection with cid: %d failed", __func__, data->cid); + + if (ipc_seq_valid(message->aseq)) + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + + return 0; + } + + request = ril_request_find_token(data_connection->token); + + if (data->status == IPC_GPRS_STATUS_ENABLED) { + if (data_connection->enabled) { + if (request != NULL && request->request == RIL_REQUEST_DEACTIVATE_DATA_CALL) + goto error; + else + RIL_LOGD("%s: Data connection with cid %d is already enabled", __func__, data_connection->cid); + } else { + rc = ril_data_connection_enable(data_connection); + if (rc < 0) + goto error; + + if (request != NULL && request->request == RIL_REQUEST_SETUP_DATA_CALL) { + memset(&response, 0, sizeof(response)); +#if RIL_VERSION >= 6 + response.status = ipc2ril_gprs_fail_cause(data->fail_cause); + response.cid = data_connection->cid; + response.active = 2; + response.type = strdup("IP"); + + if (data_connection->iface != NULL) + response.ifname = strdup(data_connection->iface); + + if (data_connection->ip != NULL) + response.addresses = strdup(data_connection->ip); + + asprintf(&response.dnses, "%s %s", data_connection->dns1, data_connection->dns2); + + if (data_connection->gateway != NULL) + response.gateways = strdup(data_connection->gateway); +#else + asprintf(&response[0], "%d", gprs_connection->cid); + + if (data_connection->iface != NULL) + response[1] = strdup(data_connection->iface); + + if (data_connection->ip != NULL) + response[2] = strdup(data_connection->ip); +#endif + + ril_request_complete(data_connection->token, RIL_E_SUCCESS, &response, sizeof(response)); + data_connection->token = NULL; + +#if RIL_VERSION >= 6 + if (response.type != NULL) + free(response.type); + + if (response.ifname != NULL) + free(response.ifname); + + if (response.addresses != NULL) + free(response.addresses); + + if (response.gateways != NULL) + free(response.gateways); + + if (response.dnses != NULL) + free(response.dnses); +#else + for (i = 0; i < 3; i++) { + if (reponse[i] != NULL) + free(response[i]); + } +#endif + } else { + RIL_LOGD("%s: Data connection with cid: %d got unexpectedly enabled", __func__, data_connection->cid); + } + } + } else if (data->status == IPC_GPRS_STATUS_DISABLED || data->status == IPC_GPRS_STATUS_NOT_ENABLED) { + if (data_connection->enabled) { + rc = ril_data_connection_disable(data_connection); + if (rc < 0) + goto error; + + ril_data_connection_stop(data_connection); + + if (request != NULL && request->request == RIL_REQUEST_DEACTIVATE_DATA_CALL) + ril_request_complete(request->token, RIL_E_SUCCESS, NULL, 0); + else + RIL_LOGD("%s: Data connection with cid: %d got unexpectedly disabled", __func__, data->cid); + } else { + if (request != NULL && request->request == RIL_REQUEST_SETUP_DATA_CALL) { +#if RIL_VERSION >= 6 + memset(&response, 0, sizeof(response)); + response.status = ipc2ril_gprs_fail_cause(data->fail_cause); + + ril_request_complete(request->token, RIL_E_SUCCESS, (void *) &response, sizeof(response)); + // Avoid completing the request twice + request = NULL; +#else + fail_cause = ipc2ril_gprs_fail_cause(data->fail_cause); + + ril_request_data_set_uniq(RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, (void *) &fail_cause, sizeof(fail_cause)); +#endif + goto error; + } else { + RIL_LOGD("%s: Data connection with cid: %d is already disabled", __func__, data_connection->cid); + } + } + } + + if (request == NULL) { + rc = ipc_fmt_send(0, IPC_GPRS_PDP_CONTEXT, IPC_TYPE_GET, NULL, 0); + if (rc < 0) + goto error; + } + + goto complete; + +error: + ril_data_connection_stop(data_connection); + + if (request != NULL) + ril_request_complete(request->token, RIL_E_GENERIC_FAILURE, NULL, 0); + +complete: + return 0; +} + +int ril_request_last_data_call_fail_cause(void *data, size_t size, + RIL_Token token) +{ + void *fail_cause_data; + size_t fail_cause_size; + int fail_cause; + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + fail_cause_size = ril_request_data_size_get(RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE); + fail_cause_data = ril_request_data_get(RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE); + + if (fail_cause_data != NULL && fail_cause_size >= sizeof(int)) { + fail_cause = *((int *) fail_cause_data); + free(fail_cause_data); + } else { + fail_cause = PDP_FAIL_ERROR_UNSPECIFIED; + } + + ril_request_complete(token, RIL_E_SUCCESS, (void *) &fail_cause, sizeof(fail_cause)); + + return RIL_REQUEST_COMPLETED; +} @@ -1,160 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> - * - * Based on CyanogenMod Smdk4210RIL implementation - * Copyright (C) 2011 The CyanogenMod Project - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#define LOG_TAG "RIL-DISP" -#include <utils/Log.h> - -#include "samsung-ril.h" -#include "util.h" - -#if RIL_VERSION >= 6 -void ipc2ril_rssi(unsigned char rssi, RIL_SignalStrength_v6 *ss) -#else -void ipc2ril_rssi(unsigned char rssi, RIL_SignalStrength *ss) -#endif -{ - int asu = 0; - - if (ss == NULL) - return; - - if (rssi > 0x6f) { - asu = 0; - } else { - asu = (((rssi - 0x71) * -1) - ((rssi - 0x71) * -1) % 2) / 2; - if (asu > 31) - asu = 31; - } - - RIL_LOGD("Signal Strength is %d\n", asu); - -#if RIL_VERSION >= 6 - memset(ss, 0, sizeof(RIL_SignalStrength_v6)); - memset(&ss->LTE_SignalStrength, -1, sizeof(ss->LTE_SignalStrength)); -#else - memset(ss, 0, sizeof(RIL_SignalStrength)); -#endif - - ss->GW_SignalStrength.signalStrength = asu; - ss->GW_SignalStrength.bitErrorRate = 99; -} - -#if RIL_VERSION >= 6 -void ipc2ril_bars(unsigned char bars, RIL_SignalStrength_v6 *ss) -#else -void ipc2ril_bars(unsigned char bars, RIL_SignalStrength *ss) -#endif -{ - int asu = 0; - - if (ss == NULL) - return; - - switch (bars) { - case 0 : asu = 1; break; - case 1 : asu = 3; break; - case 2 : asu = 5; break; - case 3 : asu = 8; break; - case 4 : asu = 12; break; - case 5 : asu = 15; break; - default : asu = bars; break; - } - - RIL_LOGD("Signal Strength is %d\n", asu); - -#if RIL_VERSION >= 6 - memset(ss, 0, sizeof(RIL_SignalStrength_v6)); - memset(&ss->LTE_SignalStrength, -1, sizeof(ss->LTE_SignalStrength)); -#else - memset(ss, 0, sizeof(RIL_SignalStrength)); -#endif - - ss->GW_SignalStrength.signalStrength = asu; - ss->GW_SignalStrength.bitErrorRate = 99; -} - -void ril_request_signal_strength(RIL_Token t) -{ - unsigned char request = 1; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - ipc_fmt_send(IPC_DISP_ICON_INFO, IPC_TYPE_GET, &request, sizeof(request), ril_request_get_id(t)); -} - -void ipc_disp_icon_info(struct ipc_message_info *info) -{ - struct ipc_disp_icon_info *icon_info; -#if RIL_VERSION >= 6 - RIL_SignalStrength_v6 ss; -#else - RIL_SignalStrength ss; -#endif - - if (info->data == NULL || info->length < sizeof(struct ipc_disp_icon_info)) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_OFF, RIL_TOKEN_NULL)) - return; - - icon_info = (struct ipc_disp_icon_info *) info->data; - - if (info->type == IPC_TYPE_RESP) { - ipc2ril_rssi(icon_info->rssi, &ss); - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, &ss, sizeof(ss)); - - } else { - ipc2ril_bars(icon_info->bars, &ss); - ril_request_unsolicited(RIL_UNSOL_SIGNAL_STRENGTH, &ss, sizeof(ss)); - } - - return; - -error: - if (info->type == IPC_TYPE_RESP) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_disp_rssi_info(struct ipc_message_info *info) -{ - struct ipc_disp_rssi_info *rssi_info; -#if RIL_VERSION >= 6 - RIL_SignalStrength_v6 ss; -#else - RIL_SignalStrength ss; -#endif - int rssi; - - if (info->data == NULL || info->length < sizeof(struct ipc_disp_rssi_info)) - return; - - if (ril_radio_state_complete(RADIO_STATE_OFF, RIL_TOKEN_NULL)) - return; - - rssi_info = (struct ipc_disp_rssi_info *) info->data; - - ipc2ril_rssi(rssi_info->rssi, &ss); - - ril_request_unsolicited(RIL_UNSOL_SIGNAL_STRENGTH, &ss, sizeof(ss)); -} @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,178 +17,263 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ -#define LOG_TAG "RIL-GEN" -#include <utils/Log.h> +#include <stdlib.h> -#include "samsung-ril.h" -#include "util.h" +#define LOG_TAG "RIL" +#include <utils/Log.h> -/* - * IPC_GEN_PHONE_RES has shared aseq (in the header), group, index and type (in the data) - * with the original request it responds to. - * On this implementation, we just check aseq and command (group and index). - * aseq permits to identify the queued request and do what's wanted. - * It can be either call a function with the struct ipc_message_info, - * complete the request to RILJ (with or without an error), - * return to RILJ if there is an error in this response. - * - * It would have been possible to deal with group, index and type only and use - * callback functions. Though, what is currently being used is more a "standard" - * error catch system, that requires less code (no particular function), while - * it also permits using custom functions, when IPC_GEN_PHONE_RES code is - * request-specific. - * - * On a custom function, don't forget to get a clean new aseq if you're going to - * send some data to the modem, just liek this: - * aseq = ril_request_reg_id(ril_request_get_token(info->aseq)); - * - * Please use the GEN_PHONE_RES engine as often as possible! - */ +#include <samsung-ril.h> +#include <utils.h> -/* - * GEN expects functions - */ - -int ipc_gen_phone_res_expect_register(unsigned char aseq, unsigned short command, - void (*func)(struct ipc_message_info *info), int complete, int abort) +int ipc_gen_phone_res_expect_register(struct ril_client *client, + unsigned char aseq, unsigned short command, + int (*callback)(struct ipc_message *message), + int complete, int abort) { - struct ipc_gen_phone_res_expect_info *expect; + struct ipc_gen_phone_res_expect *expect; + struct ipc_fmt_data *data; struct list_head *list_end; struct list_head *list; - expect = calloc(1, sizeof(struct ipc_gen_phone_res_expect_info)); - if (expect == NULL) + if (client == NULL || client->data == NULL) return -1; + data = (struct ipc_fmt_data *) client->data; + + RIL_CLIENT_LOCK(client); + + expect = calloc(1, sizeof(struct ipc_gen_phone_res_expect)); expect->aseq = aseq; expect->command = command; - expect->func = func; + expect->callback = callback; expect->complete = complete; expect->abort = abort; - list_end = ril_data.generic_responses; + list_end = data->gen_phone_res_expect; while (list_end != NULL && list_end->next != NULL) list_end = list_end->next; - list = list_head_alloc((void *) expect, list_end, NULL); + list = list_head_alloc(list_end, NULL, (void *) expect); + + if (data->gen_phone_res_expect == NULL) + data->gen_phone_res_expect = list; - if (ril_data.generic_responses == NULL) - ril_data.generic_responses = list; + RIL_CLIENT_UNLOCK(client); return 0; } -void ipc_gen_phone_res_expect_unregister(struct ipc_gen_phone_res_expect_info *expect) +int ipc_gen_phone_res_expect_unregister(struct ril_client *client, + struct ipc_gen_phone_res_expect *expect) { + struct ipc_fmt_data *data; struct list_head *list; - if (expect == NULL) - return; + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_fmt_data *) client->data; + + RIL_CLIENT_LOCK(client); - list = ril_data.generic_responses; + list = data->gen_phone_res_expect; while (list != NULL) { if (list->data == (void *) expect) { - memset(expect, 0, sizeof(struct ipc_gen_phone_res_expect_info)); + memset(expect, 0, sizeof(struct ipc_gen_phone_res_expect)); free(expect); - if (list == ril_data.generic_responses) - ril_data.generic_responses = list->next; + if (list == data->gen_phone_res_expect) + data->gen_phone_res_expect = list->next; list_head_free(list); break; } + list_continue: list = list->next; } + + RIL_CLIENT_UNLOCK(client); + + return 0; } -struct ipc_gen_phone_res_expect_info *ipc_gen_phone_res_expect_info_find_aseq(unsigned char aseq) +int ipc_gen_phone_res_expect_flush(struct ril_client *client) { - struct ipc_gen_phone_res_expect_info *expect; + struct ipc_gen_phone_res_expect *expect; + struct ipc_fmt_data *data; struct list_head *list; + struct list_head *list_next; + + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_fmt_data *) client->data; + + RIL_CLIENT_LOCK(client); + + list = data->gen_phone_res_expect; + while (list != NULL) { + if (list->data != NULL) { + expect = (struct ipc_gen_phone_res_expect *) list->data; + memset(expect, 0, sizeof(struct ipc_gen_phone_res_expect)); + free(expect); + } + + if (list == data->gen_phone_res_expect) + data->gen_phone_res_expect = list->next; + + list_next = list->next; + + list_head_free(list); + +list_continue: + list = list_next; + } + + RIL_CLIENT_UNLOCK(client); + + return 0; +} + +struct ipc_gen_phone_res_expect *ipc_gen_phone_res_expect_find_aseq(struct ril_client *client, + unsigned char aseq) +{ + struct ipc_gen_phone_res_expect *expect; + struct ipc_fmt_data *data; + struct list_head *list; + + if (client == NULL || client->data == NULL) + return NULL; + + data = (struct ipc_fmt_data *) client->data; - list = ril_data.generic_responses; + RIL_CLIENT_LOCK(client); + + list = data->gen_phone_res_expect; while (list != NULL) { - expect = (struct ipc_gen_phone_res_expect_info *) list->data; - if (expect == NULL) + if (list->data == NULL) goto list_continue; - if (expect->aseq == aseq) + expect = (struct ipc_gen_phone_res_expect *) list->data; + + if (expect->aseq == aseq) { + RIL_CLIENT_UNLOCK(client); return expect; + } list_continue: list = list->next; } + RIL_CLIENT_UNLOCK(client); + return NULL; } -int ipc_gen_phone_res_expect_to_func(unsigned char aseq, unsigned short command, - void (*func)(struct ipc_message_info *info)) +int ipc_gen_phone_res_expect_callback(unsigned char aseq, unsigned short command, + int (*callback)(struct ipc_message *message)) { - return ipc_gen_phone_res_expect_register(aseq, command, func, 0, 0); + struct ril_client *client; + int rc; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL) + return -1; + + rc = ipc_gen_phone_res_expect_register(client, aseq, command, callback, 0, 0); + if (rc < 0) + return -1; + + return 0; } -int ipc_gen_phone_res_expect_to_complete(unsigned char aseq, unsigned short command) +int ipc_gen_phone_res_expect_complete(unsigned char aseq, unsigned short command) { - return ipc_gen_phone_res_expect_register(aseq, command, NULL, 1, 0); + struct ril_client *client; + int rc; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL) + return -1; + + rc = ipc_gen_phone_res_expect_register(client, aseq, command, NULL, 1, 0); + if (rc < 0) + return -1; + + return 0; } -int ipc_gen_phone_res_expect_to_abort(unsigned char aseq, unsigned short command) +int ipc_gen_phone_res_expect_abort(unsigned char aseq, unsigned short command) { - return ipc_gen_phone_res_expect_register(aseq, command, NULL, 0, 1); -} + struct ril_client *client; + int rc; -/* - * GEN dequeue function - */ + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL) + return -1; + + rc = ipc_gen_phone_res_expect_register(client, aseq, command, NULL, 0, 1); + if (rc < 0) + return -1; + + return 0; +} -void ipc_gen_phone_res(struct ipc_message_info *info) +int ipc_gen_phone_res(struct ipc_message *message) { - struct ipc_gen_phone_res_expect_info *expect; - struct ipc_gen_phone_res *phone_res; - RIL_Errno e; + struct ipc_gen_phone_res_expect *expect; + struct ipc_gen_phone_res_data *data; + struct ril_client *client; + RIL_Errno error; int rc; - if (info->data == NULL || info->length < sizeof(struct ipc_gen_phone_res)) - return; + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL) + return -1; - phone_res = (struct ipc_gen_phone_res *) info->data; - expect = ipc_gen_phone_res_expect_info_find_aseq(info->aseq); + data = (struct ipc_gen_phone_res_data *) message->data; + expect = ipc_gen_phone_res_expect_find_aseq(client, message->aseq); if (expect == NULL) { - RIL_LOGD("aseq: 0x%x not found in the IPC_GEN_PHONE_RES queue", info->aseq); - return; + RIL_LOGD("Ignoring generic response for command %s", ipc_command_string(IPC_COMMAND(data->group, data->index))); + return 0; } - RIL_LOGD("aseq: 0x%x found in the IPC_GEN_PHONE_RES queue!", info->aseq); - - if (expect->command != IPC_COMMAND(phone_res)) { - RIL_LOGE("IPC_GEN_PHONE_RES aseq (0x%x) doesn't match the queued one with command (0x%x)", - expect->aseq, expect->command); - - if (expect->func != NULL) { - RIL_LOGE("Not safe to run the custom function, reporting generic failure"); - ril_request_complete(ril_request_get_token(expect->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - goto unregister; - } + if (IPC_COMMAND(data->group, data->index) != expect->command) { + RIL_LOGE("Generic response commands mismatch: %s/%s", ipc_command_string(IPC_COMMAND(data->group, data->index)), ipc_command_string(expect->command)); + goto error; } - if (expect->func != NULL) { - expect->func(info); - goto unregister; + RIL_LOGD("Generic response was expected"); + + if (expect->callback != NULL) { + rc = expect->callback(message); + goto complete; } - rc = ipc_gen_phone_res_check(phone_res); + rc = ipc_gen_phone_res_check(data); if (rc < 0) - e = RIL_E_GENERIC_FAILURE; + error = RIL_E_GENERIC_FAILURE; else - e = RIL_E_SUCCESS; + error = RIL_E_SUCCESS; + + if (expect->complete || (expect->abort && error == RIL_E_GENERIC_FAILURE)) + ril_request_complete(ipc_fmt_request_token(message->aseq), error, NULL, 0); + + rc = 0; + goto complete; + +error: + rc = -1; - if (expect->complete || (expect->abort && e == RIL_E_GENERIC_FAILURE)) - ril_request_complete(ril_request_get_token(expect->aseq), e, NULL, 0); +complete: + if (expect != NULL) + ipc_gen_phone_res_expect_unregister(client, expect); -unregister: - ipc_gen_phone_res_expect_unregister(expect); + return rc; } @@ -1,1075 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> - * Copyright (C) 2011 Denis 'GNUtoo' Carikli <GNUtoo@no-log.org> - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <netinet/in.h> -#include <arpa/inet.h> - -#define LOG_TAG "RIL-GPRS" -#include <utils/Log.h> -#include <cutils/properties.h> - -#if RIL_VERSION >= 6 -#include <netutils/ifc.h> -#endif - -#include "samsung-ril.h" -#include "util.h" - -#if RIL_VERSION >= 6 -RIL_DataCallFailCause ipc2ril_gprs_fail_cause(unsigned short fail_cause) -#else -RIL_LastDataCallActivateFailCause ipc2ril_gprs_fail_cause(unsigned short fail_cause) -#endif -{ - switch (fail_cause) { - - case IPC_GPRS_FAIL_INSUFFICIENT_RESOURCES: - return PDP_FAIL_INSUFFICIENT_RESOURCES; - case IPC_GPRS_FAIL_MISSING_UKNOWN_APN: - return PDP_FAIL_MISSING_UKNOWN_APN; - case IPC_GPRS_FAIL_UNKNOWN_PDP_ADDRESS_TYPE: - return PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE; - case IPC_GPRS_FAIL_USER_AUTHENTICATION: - return PDP_FAIL_USER_AUTHENTICATION; - case IPC_GPRS_FAIL_ACTIVATION_REJECT_GGSN: - return PDP_FAIL_ACTIVATION_REJECT_GGSN; - case IPC_GPRS_FAIL_ACTIVATION_REJECT_UNSPECIFIED: - return PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED; - case IPC_GPRS_FAIL_SERVICE_OPTION_NOT_SUPPORTED: - return PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED; - case IPC_GPRS_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED: - return PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED; - case IPC_GPRS_FAIL_SERVICE_OPTION_OUT_OF_ORDER: - return PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER; - case IPC_GPRS_FAIL_NSAPI_IN_USE: - return PDP_FAIL_NSAPI_IN_USE; - default: - return PDP_FAIL_ERROR_UNSPECIFIED; - } -} - -int ipc2ril_gprs_connection_active(unsigned char state) -{ - switch (state) { - case IPC_GPRS_STATE_DISABLED: - return 1; - case IPC_GPRS_STATE_ENABLED: - return 2; - case IPC_GPRS_STATE_NOT_ENABLED: - default: - return 0; - } -} - -int ril_gprs_connection_register(int cid) -{ - struct ril_gprs_connection *gprs_connection; - struct list_head *list_end; - struct list_head *list; - - gprs_connection = calloc(1, sizeof(struct ril_gprs_connection)); - if (gprs_connection == NULL) - return -1; - - gprs_connection->cid = cid; - - list_end = ril_data.gprs_connections; - while (list_end != NULL && list_end->next != NULL) - list_end = list_end->next; - - list = list_head_alloc((void *) gprs_connection, list_end, NULL); - - if (ril_data.gprs_connections == NULL) - ril_data.gprs_connections = list; - - return 0; -} - -void ril_gprs_connection_unregister(struct ril_gprs_connection *gprs_connection) -{ - struct list_head *list; - - if (gprs_connection == NULL) - return; - - list = ril_data.gprs_connections; - while (list != NULL) { - if (list->data == (void *) gprs_connection) { - memset(gprs_connection, 0, sizeof(struct ril_gprs_connection)); - free(gprs_connection); - - if (list == ril_data.gprs_connections) - ril_data.gprs_connections = list->next; - - list_head_free(list); - - break; - } -list_continue: - list = list->next; - } -} - -struct ril_gprs_connection *ril_gprs_connection_find_cid(int cid) -{ - struct ril_gprs_connection *gprs_connection; - struct list_head *list; - - list = ril_data.gprs_connections; - while (list != NULL) { - gprs_connection = (struct ril_gprs_connection *) list->data; - if (gprs_connection == NULL) - goto list_continue; - - if (gprs_connection->cid == cid) - return gprs_connection; - -list_continue: - list = list->next; - } - - return NULL; -} - -struct ril_gprs_connection *ril_gprs_connection_find_token(RIL_Token t) -{ - struct ril_gprs_connection *gprs_connection; - struct list_head *list; - - list = ril_data.gprs_connections; - while (list != NULL) { - gprs_connection = (struct ril_gprs_connection *) list->data; - if (gprs_connection == NULL) - goto list_continue; - - if (gprs_connection->token == t) - return gprs_connection; - -list_continue: - list = list->next; - } - - return NULL; -} - -struct ril_gprs_connection *ril_gprs_connection_start(void) -{ - struct ipc_client_gprs_capabilities gprs_capabilities; - struct ril_gprs_connection *gprs_connection; - struct ipc_client *ipc_client; - struct list_head *list; - int cid, cid_max; - int rc; - int i; - - if (ril_data.ipc_fmt_client == NULL || ril_data.ipc_fmt_client->data == NULL) - return NULL; - - ipc_client = (struct ipc_client *) ril_data.ipc_fmt_client->data; - - ipc_client_gprs_get_capabilities(ipc_client, &gprs_capabilities); - cid_max = gprs_capabilities.cid_max; - - for (i = 0 ; i < cid_max ; i++) { - cid = i + 1; - list = ril_data.gprs_connections; - while (list != NULL) { - if (list->data == NULL) - goto list_continue; - - gprs_connection = (struct ril_gprs_connection *) list->data; - if (gprs_connection->cid == cid) { - cid = 0; - break; - } - -list_continue: - list = list->next; - } - - if (cid > 0) - break; - } - - if (cid <= 0) { - RIL_LOGE("Unable to find an unused cid, aborting"); - return NULL; - } - - RIL_LOGD("Using GPRS connection cid: %d", cid); - rc = ril_gprs_connection_register(cid); - if (rc < 0) - return NULL; - - gprs_connection = ril_gprs_connection_find_cid(cid); - return gprs_connection; -} - -void ril_gprs_connection_stop(struct ril_gprs_connection *gprs_connection) -{ - if (gprs_connection == NULL) - return; - - if (gprs_connection->interface != NULL) - free(gprs_connection->interface); - - ril_gprs_connection_unregister(gprs_connection); -} - -void ipc_gprs_pdp_context_enable_complete(struct ipc_message_info *info) -{ - struct ipc_gen_phone_res *phone_res; - struct ril_gprs_connection *gprs_connection; - int rc; - - phone_res = (struct ipc_gen_phone_res *) info->data; - gprs_connection = ril_gprs_connection_find_token(ril_request_get_token(info->aseq)); - - if (!gprs_connection) { - RIL_LOGE("Unable to find GPRS connection, aborting"); - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - rc = ipc_gen_phone_res_check(phone_res); - if (rc < 0) { - RIL_LOGE("There was an error, aborting PDP context complete"); - - gprs_connection->fail_cause = PDP_FAIL_ERROR_UNSPECIFIED; - gprs_connection->token = RIL_TOKEN_NULL; - ril_data.state.gprs_last_failed_cid = gprs_connection->cid; - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - RIL_LOGD("Waiting for IP configuration!"); -} - -void ipc_gprs_define_pdp_context_complete(struct ipc_message_info *info) -{ - struct ipc_gen_phone_res *phone_res; - struct ril_gprs_connection *gprs_connection; - struct ril_request_info *request; - int aseq; - int rc; - - phone_res = (struct ipc_gen_phone_res *) info->data; - gprs_connection = ril_gprs_connection_find_token(ril_request_get_token(info->aseq)); - - if (!gprs_connection) { - RIL_LOGE("Unable to find GPRS connection, aborting"); - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - rc = ipc_gen_phone_res_check(phone_res); - if (rc < 0) { - RIL_LOGE("There was an error, aborting define PDP context complete"); - - gprs_connection->fail_cause = PDP_FAIL_ERROR_UNSPECIFIED; - gprs_connection->token = RIL_TOKEN_NULL; - ril_data.state.gprs_last_failed_cid = gprs_connection->cid; - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - request = ril_request_info_find_id(info->aseq); - aseq = ril_request_id_get(); - - if (request != NULL) - request->id = aseq; - - ipc_gen_phone_res_expect_to_func(aseq, IPC_GPRS_PDP_CONTEXT, - ipc_gprs_pdp_context_enable_complete); - - ipc_fmt_send(IPC_GPRS_PDP_CONTEXT, IPC_TYPE_SET, - (void *) &(gprs_connection->context), - sizeof(struct ipc_gprs_pdp_context_set), aseq); -} - -void ipc_gprs_port_list_complete(struct ipc_message_info *info) -{ - struct ipc_gen_phone_res *phone_res; - struct ril_gprs_connection *gprs_connection; - struct ril_request_info *request; - int aseq; - int rc; - - phone_res = (struct ipc_gen_phone_res *) info->data; - gprs_connection = ril_gprs_connection_find_token(ril_request_get_token(info->aseq)); - - if (!gprs_connection) { - RIL_LOGE("Unable to find GPRS connection, aborting"); - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - rc = ipc_gen_phone_res_check(phone_res); - if (rc < 0) { - RIL_LOGE("There was an error, aborting port list complete"); - - gprs_connection->fail_cause = PDP_FAIL_ERROR_UNSPECIFIED; - gprs_connection->token = RIL_TOKEN_NULL; - ril_data.state.gprs_last_failed_cid = gprs_connection->cid; - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - request = ril_request_info_find_id(info->aseq); - aseq = ril_request_id_get(); - - if (request != NULL) - request->id = aseq; - ipc_gen_phone_res_expect_to_func(aseq, IPC_GPRS_DEFINE_PDP_CONTEXT, - ipc_gprs_define_pdp_context_complete); - - ipc_fmt_send(IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET, - (void *) &(gprs_connection->define_context), - sizeof(struct ipc_gprs_define_pdp_context), - aseq); -} - -void ril_request_setup_data_call(RIL_Token t, void *data, int length) -{ - struct ril_gprs_connection *gprs_connection = NULL; - struct ipc_client_gprs_capabilities gprs_capabilities; - struct ipc_gprs_port_list port_list; - struct ipc_client *ipc_client; - - char *username = NULL; - char *password = NULL; - char *apn = NULL; - - if (data == NULL || length < (int) (4 * sizeof(char *))) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - if (ril_data.ipc_fmt_client == NULL || ril_data.ipc_fmt_client->data == NULL) - goto error; - - ipc_client = (struct ipc_client *) ril_data.ipc_fmt_client->data; - - apn = ((char **) data)[2]; - username = ((char **) data)[3]; - password = ((char **) data)[4]; - - RIL_LOGD("Requesting data connection to APN '%s'\n", apn); - - gprs_connection = ril_gprs_connection_start(); - - if (!gprs_connection) { - RIL_LOGE("Unable to create GPRS connection, aborting"); - - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - gprs_connection->token = t; - - // Create the structs with the apn - ipc_gprs_define_pdp_context_setup(&(gprs_connection->define_context), - gprs_connection->cid, 1, apn); - - // Create the structs with the username/password tuple - ipc_gprs_pdp_context_setup(&(gprs_connection->context), - gprs_connection->cid, 1, username, password); - - ipc_client_gprs_get_capabilities(ipc_client, &gprs_capabilities); - - // If the device has the capability, deal with port list - if (gprs_capabilities.port_list) { - ipc_gprs_port_list_setup(&port_list); - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_GPRS_PORT_LIST, - ipc_gprs_port_list_complete); - - ipc_fmt_send(IPC_GPRS_PORT_LIST, IPC_TYPE_SET, - (void *) &port_list, sizeof(struct ipc_gprs_port_list), ril_request_get_id(t)); - } else { - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_GPRS_DEFINE_PDP_CONTEXT, - ipc_gprs_define_pdp_context_complete); - - ipc_fmt_send(IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET, - (void *) &(gprs_connection->define_context), - sizeof(struct ipc_gprs_define_pdp_context), ril_request_get_id(t)); - } - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_gprs_ip_configuration(struct ipc_message_info *info) -{ - struct ril_gprs_connection *gprs_connection; - struct ipc_gprs_ip_configuration *ip_configuration; - - if (info->data == NULL || info->length < sizeof(struct ipc_gprs_ip_configuration)) - goto error; - - ip_configuration = (struct ipc_gprs_ip_configuration *) info->data; - - gprs_connection = ril_gprs_connection_find_cid(ip_configuration->cid); - - if (!gprs_connection) { - RIL_LOGE("Unable to find GPRS connection, aborting"); - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - RIL_LOGD("Obtained IP Configuration"); - - // Copy the obtained IP configuration to the GPRS connection structure - memcpy(&(gprs_connection->ip_configuration), - ip_configuration, sizeof(struct ipc_gprs_ip_configuration)); - - RIL_LOGD("Waiting for GPRS call status"); - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_gprs_pdp_context_disable_complete(struct ipc_message_info *info) -{ - struct ipc_gen_phone_res *phone_res; - struct ril_gprs_connection *gprs_connection; - int rc; - - phone_res = (struct ipc_gen_phone_res *) info->data; - gprs_connection = ril_gprs_connection_find_token(ril_request_get_token(info->aseq)); - - if (!gprs_connection) { - RIL_LOGE("Unable to find GPRS connection, aborting"); - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - rc = ipc_gen_phone_res_check(phone_res); - if (rc < 0) { - RIL_LOGE("There was an error, aborting PDP context complete"); - - // RILJ is not going to ask for fail reason - ril_gprs_connection_stop(gprs_connection); - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - RIL_LOGD("Waiting for GPRS call status"); -} - -void ril_request_deactivate_data_call(RIL_Token t, void *data, int length) -{ - struct ril_gprs_connection *gprs_connection; - struct ipc_gprs_pdp_context_set context; - - char *cid; - int rc; - - if (data == NULL || length < (int) sizeof(char *)) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - cid = ((char **) data)[0]; - - gprs_connection = ril_gprs_connection_find_cid(atoi(cid)); - - if (!gprs_connection) { - RIL_LOGE("Unable to find GPRS connection, aborting"); - - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - gprs_connection->token = t; - - ipc_gprs_pdp_context_setup(&context, gprs_connection->cid, 0, NULL, NULL); - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_GPRS_PDP_CONTEXT, - ipc_gprs_pdp_context_disable_complete); - - ipc_fmt_send(IPC_GPRS_PDP_CONTEXT, IPC_TYPE_SET, - (void *) &context, sizeof(struct ipc_gprs_pdp_context_set), ril_request_get_id(t)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -#if RIL_VERSION >= 6 -int ipc_gprs_connection_enable(struct ril_gprs_connection *gprs_connection, - RIL_Data_Call_Response_v6 *setup_data_call_response) -#else -int ipc_gprs_connection_enable(struct ril_gprs_connection *gprs_connection, - char **setup_data_call_response) -#endif -{ - struct ipc_client *ipc_client; - struct ipc_gprs_ip_configuration *ip_configuration; - - char *interface = NULL; - char *ip; - char *gateway; - char *subnet_mask; - in_addr_t subnet_mask_addr; - char *dns1; - char *dns2; - - char prop_name[PROPERTY_KEY_MAX]; - - int rc; - - if (gprs_connection == NULL || setup_data_call_response == NULL) - return -EINVAL; - - if (ril_data.ipc_fmt_client == NULL || ril_data.ipc_fmt_client->data == NULL) - return -EINVAL; - - ipc_client = (struct ipc_client *) ril_data.ipc_fmt_client->data; - - ip_configuration = &(gprs_connection->ip_configuration); - - asprintf(&ip, "%i.%i.%i.%i", - (ip_configuration->ip)[0], - (ip_configuration->ip)[1], - (ip_configuration->ip)[2], - (ip_configuration->ip)[3]); - - // FIXME: gateway isn't reliable! - asprintf(&gateway, "%i.%i.%i.%i", - (ip_configuration->ip)[0], - (ip_configuration->ip)[1], - (ip_configuration->ip)[2], - (ip_configuration->ip)[3]); - - // FIXME: subnet isn't reliable! - asprintf(&subnet_mask, "255.255.255.255"); - - asprintf(&dns1, "%i.%i.%i.%i", - (ip_configuration->dns1)[0], - (ip_configuration->dns1)[1], - (ip_configuration->dns1)[2], - (ip_configuration->dns1)[3]); - asprintf(&dns2, "%i.%i.%i.%i", - (ip_configuration->dns2)[0], - (ip_configuration->dns2)[1], - (ip_configuration->dns2)[2], - (ip_configuration->dns2)[3]); - - rc = ipc_client_gprs_activate(ipc_client, gprs_connection->cid); - if (rc < 0) { - // This is not a critical issue - RIL_LOGE("Failed to activate interface!"); - } - - interface = ipc_client_gprs_get_iface(ipc_client, gprs_connection->cid); - if (interface == NULL) { - // This is not a critical issue, fallback to rmnet - RIL_LOGE("Failed to get interface name!"); - asprintf(&interface, "rmnet%d", gprs_connection->cid - 1); - } - - if (gprs_connection->interface == NULL && interface != NULL) { - gprs_connection->interface = strdup(interface); - } - - RIL_LOGD("Using net interface: %s\n", interface); - - RIL_LOGD("GPRS configuration: iface: %s, ip:%s, " - "gateway:%s, subnet_mask:%s, dns1:%s, dns2:%s", - interface, ip, gateway, subnet_mask, dns1, dns2); - - subnet_mask_addr = inet_addr(subnet_mask); - -#if RIL_VERSION >= 6 - rc = ifc_configure(interface, inet_addr(ip), - ipv4NetmaskToPrefixLength(subnet_mask_addr), - inet_addr(gateway), - inet_addr(dns1), inet_addr(dns2)); -#else - rc = ifc_configure(interface, inet_addr(ip), - subnet_mask_addr, - inet_addr(gateway), - inet_addr(dns1), inet_addr(dns2)); -#endif - - if (rc < 0) { - RIL_LOGE("ifc_configure failed"); - - free(interface); - return -1; - } - - snprintf(prop_name, PROPERTY_KEY_MAX, "net.%s.dns1", interface); - property_set(prop_name, dns1); - snprintf(prop_name, PROPERTY_KEY_MAX, "net.%s.dns2", interface); - property_set(prop_name, dns2); - snprintf(prop_name, PROPERTY_KEY_MAX, "net.%s.gw", interface); - property_set(prop_name, gateway); - -#if RIL_VERSION >= 6 - setup_data_call_response->status = 0; - setup_data_call_response->cid = gprs_connection->cid; - setup_data_call_response->active = 1; - setup_data_call_response->type = strdup("IP"); - - setup_data_call_response->ifname = interface; - setup_data_call_response->addresses = ip; - setup_data_call_response->gateways = gateway; - asprintf(&setup_data_call_response->dnses, "%s %s", dns1, dns2); -#else - asprintf(&(setup_data_call_response[0]), "%d", gprs_connection->cid); - setup_data_call_response[1] = interface; - setup_data_call_response[2] = ip; - - free(gateway); -#endif - - free(subnet_mask); - free(dns1); - free(dns2); - - return 0; -} - -int ipc_gprs_connection_disable(struct ril_gprs_connection *gprs_connection) -{ - struct ipc_client *ipc_client; - - char *interface; - int rc; - - if (gprs_connection == NULL) - return -EINVAL; - - if (ril_data.ipc_fmt_client == NULL || ril_data.ipc_fmt_client->data == NULL) - return -EINVAL; - - ipc_client = (struct ipc_client *) ril_data.ipc_fmt_client->data; - - if (gprs_connection->interface == NULL) { - interface = ipc_client_gprs_get_iface(ipc_client, gprs_connection->cid); - if (interface == NULL) { - // This is not a critical issue, fallback to rmnet - RIL_LOGE("Failed to get interface name!"); - asprintf(&interface, "rmnet%d", gprs_connection->cid); - } - } else { - interface = gprs_connection->interface; - } - - RIL_LOGD("Using net interface: %s\n", interface); - - rc = ifc_down(interface); - - if (gprs_connection->interface == NULL) - free(interface); - - if (rc < 0) { - RIL_LOGE("ifc_down failed"); - } - - rc = ipc_client_gprs_deactivate(ipc_client, gprs_connection->cid); - if (rc < 0) { - // This is not a critical issue - RIL_LOGE("Could not deactivate interface!"); - } - - return 0; -} - -#if RIL_VERSION >= 6 -void ril_data_call_response_free(RIL_Data_Call_Response_v6 *response) -#else -void ril_data_call_response_free(RIL_Data_Call_Response *response) -#endif -{ - if (response == NULL) - return; - - if (response->type != NULL) - free(response->type); - -#if RIL_VERSION >= 6 - if (response->addresses) - free(response->addresses); - if (response->ifname) - free(response->ifname); - if (response->dnses) - free(response->dnses); - if (response->gateways) - free(response->gateways); -#else - if (response->apn) - free(response->apn); - if (response->address) - free(response->address); -#endif -} - -void ipc_gprs_call_status(struct ipc_message_info *info) -{ - struct ril_gprs_connection *gprs_connection; - struct ipc_gprs_call_status *call_status; - -#if RIL_VERSION >= 6 - RIL_Data_Call_Response_v6 setup_data_call_response; -#else - char *setup_data_call_response[3] = { NULL, NULL, NULL }; -#endif - - int rc; - - if (info->data == NULL || info->length < sizeof(struct ipc_gprs_call_status)) - goto error; - - call_status = (struct ipc_gprs_call_status *) info->data; - - memset(&setup_data_call_response, 0, sizeof(setup_data_call_response)); - - gprs_connection = ril_gprs_connection_find_cid(call_status->cid); - - if (!gprs_connection) { - RIL_LOGE("Unable to find GPRS connection, aborting"); - - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - if (call_status->fail_cause == 0) { - if (!gprs_connection->enabled && - call_status->state == IPC_GPRS_STATE_ENABLED && - gprs_connection->token != RIL_TOKEN_NULL) { - RIL_LOGD("GPRS connection is now enabled"); - - rc = ipc_gprs_connection_enable(gprs_connection, - &setup_data_call_response); - if (rc < 0) { - RIL_LOGE("Failed to enable and configure GPRS interface"); - - gprs_connection->enabled = 0; - gprs_connection->fail_cause = PDP_FAIL_ERROR_UNSPECIFIED; - ril_data.state.gprs_last_failed_cid = gprs_connection->cid; - - ril_request_complete(gprs_connection->token, - RIL_E_GENERIC_FAILURE, NULL, 0); - } else { - RIL_LOGD("GPRS interface enabled"); - - gprs_connection->enabled = 1; - - ril_request_complete(gprs_connection->token, - RIL_E_SUCCESS, &setup_data_call_response, - sizeof(setup_data_call_response)); - gprs_connection->token = RIL_TOKEN_NULL; - } -#if RIL_VERSION >= 6 - ril_data_call_response_free(&setup_data_call_response); -#else - if (setup_data_call_response[0] != NULL) - free(setup_data_call_response[0]); - if (setup_data_call_response[1] != NULL) - free(setup_data_call_response[1]); - if (setup_data_call_response[2] != NULL) - free(setup_data_call_response[2]); -#endif - } else if (gprs_connection->enabled && - call_status->state == IPC_GPRS_STATE_DISABLED && - gprs_connection->token != RIL_TOKEN_NULL) { - RIL_LOGD("GPRS connection is now disabled"); - - rc = ipc_gprs_connection_disable(gprs_connection); - if (rc < 0) { - RIL_LOGE("Failed to disable GPRS interface"); - - ril_request_complete(gprs_connection->token, - RIL_E_GENERIC_FAILURE, NULL, 0); - - // RILJ is not going to ask for fail reason - ril_gprs_connection_stop(gprs_connection); - } else { - RIL_LOGD("GPRS interface disabled"); - - gprs_connection->enabled = 0; - - ril_request_complete(gprs_connection->token, - RIL_E_SUCCESS, NULL, 0); - - ril_gprs_connection_stop(gprs_connection); - } - } else { - RIL_LOGE("GPRS connection reported as changed though state is not OK:" - "\n\tgprs_connection->enabled=%d\n\tgprs_connection->token=0x%x", - gprs_connection->enabled, (unsigned)gprs_connection->token); - - ril_unsol_data_call_list_changed(); - } - } else { - if (!gprs_connection->enabled && - (call_status->state == IPC_GPRS_STATE_NOT_ENABLED || - call_status->state == IPC_GPRS_STATE_DISABLED) && - gprs_connection->token != RIL_TOKEN_NULL) { - RIL_LOGE("Failed to enable GPRS connection"); - - gprs_connection->enabled = 0; - gprs_connection->fail_cause = - ipc2ril_gprs_fail_cause(call_status->fail_cause); - ril_data.state.gprs_last_failed_cid = gprs_connection->cid; - - ril_request_complete(gprs_connection->token, - RIL_E_GENERIC_FAILURE, NULL, 0); - gprs_connection->token = RIL_TOKEN_NULL; - - ril_unsol_data_call_list_changed(); - } else if (gprs_connection->enabled && - call_status->state == IPC_GPRS_STATE_DISABLED) { - RIL_LOGE("GPRS connection suddently got disabled"); - - rc = ipc_gprs_connection_disable(gprs_connection); - if (rc < 0) { - RIL_LOGE("Failed to disable GPRS interface"); - - // RILJ is not going to ask for fail reason - ril_gprs_connection_stop(gprs_connection); - } else { - RIL_LOGE("GPRS interface disabled"); - - gprs_connection->enabled = 0; - ril_gprs_connection_stop(gprs_connection); - } - - ril_unsol_data_call_list_changed(); - } else { - RIL_LOGE("GPRS connection reported to have failed though state is OK:" - "\n\tgprs_connection->enabled=%d\n\tgprs_connection->token=0x%x", - gprs_connection->enabled, (unsigned)gprs_connection->token); - - ril_unsol_data_call_list_changed(); - } - } - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_last_data_call_fail_cause(RIL_Token t) -{ - struct ril_gprs_connection *gprs_connection; - int last_failed_cid; - int fail_cause; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - last_failed_cid = ril_data.state.gprs_last_failed_cid; - - if (!last_failed_cid) { - RIL_LOGE("No GPRS connection was reported to have failed"); - - goto fail_cause_unspecified; - } - - gprs_connection = ril_gprs_connection_find_cid(last_failed_cid); - - if (!gprs_connection) { - RIL_LOGE("Unable to find GPRS connection"); - - goto fail_cause_unspecified; - } - - fail_cause = gprs_connection->fail_cause; - - RIL_LOGD("Destroying GPRS connection with cid: %d", gprs_connection->cid); - ril_gprs_connection_stop(gprs_connection); - - goto fail_cause_return; - -fail_cause_unspecified: - fail_cause = PDP_FAIL_ERROR_UNSPECIFIED; - -fail_cause_return: - ril_data.state.gprs_last_failed_cid = 0; - - ril_request_complete(t, RIL_E_SUCCESS, &fail_cause, sizeof(fail_cause)); -} - -/* - * Some modem firmwares have a bug that will make the first cid (1) overriden - * by the current cid, thus reporting it twice, with a wrong 2nd status. - * - * This shouldn't change anything to healthy structures. - */ -#if RIL_VERSION >= 6 -void ipc_gprs_pdp_context_fix(RIL_Data_Call_Response_v6 *data_call_list, int c) -#else -void ipc_gprs_pdp_context_fix(RIL_Data_Call_Response *data_call_list, int c) -#endif -{ - int i, j, k; - - for (i = 0 ; i < c ; i++) { - for (j = i-1 ; j >= 0 ; j--) { - if (data_call_list[i].cid == data_call_list[j].cid) { - for (k = 0 ; k < c ; k++) { - if (data_call_list[k].cid == 1) { - data_call_list[i].cid = 0; - break; - } - } - - data_call_list[i].cid = 1; - } - } - } -} - -void ipc_gprs_pdp_context(struct ipc_message_info *info) -{ - struct ril_gprs_connection *gprs_connection; - struct ipc_gprs_ip_configuration *ip_configuration; - struct ipc_gprs_pdp_context_get *context; - -#if RIL_VERSION >= 6 - RIL_Data_Call_Response_v6 data_call_list[IPC_GPRS_PDP_CONTEXT_GET_DESC_COUNT]; -#else - RIL_Data_Call_Response data_call_list[IPC_GPRS_PDP_CONTEXT_GET_DESC_COUNT]; -#endif - - memset(data_call_list, 0, sizeof(data_call_list)); - - int i; - - if (info->data == NULL || info->length < sizeof(struct ipc_gprs_pdp_context_get)) - goto error; - - context = (struct ipc_gprs_pdp_context_get *) info->data; - - for (i = 0 ; i < IPC_GPRS_PDP_CONTEXT_GET_DESC_COUNT ; i++) { - data_call_list[i].cid = context->desc[i].cid; - data_call_list[i].active = - ipc2ril_gprs_connection_active(context->desc[i].state); - - if (context->desc[i].state == IPC_GPRS_STATE_ENABLED) { - gprs_connection = ril_gprs_connection_find_cid(context->desc[i].cid); - - if (gprs_connection == NULL) { - RIL_LOGE("CID %d reported as enabled but not listed here", - context->desc[i].cid); - continue; - } - - ip_configuration = &(gprs_connection->ip_configuration); - - char *addr = NULL; - asprintf(&addr, "%i.%i.%i.%i", - (ip_configuration->ip)[0], - (ip_configuration->ip)[1], - (ip_configuration->ip)[2], - (ip_configuration->ip)[3]); - -#if RIL_VERSION >= 6 - RIL_Data_Call_Response_v6 *resp = &data_call_list[i]; -#else - RIL_Data_Call_Response *resp = &data_call_list[i]; -#endif - - resp->type = strdup("IP"); - -#if RIL_VERSION < 6 - resp->address = addr; - asprintf(&(resp->apn), "%s", - gprs_connection->define_context.apn); -#else - resp->addresses = addr; - resp->gateways = strdup(addr); - resp->ifname = strdup(gprs_connection->interface); - asprintf(&resp->dnses, "%i.%i.%i.%i %i.%i.%i.%i", - ip_configuration->dns1[0], - ip_configuration->dns1[1], - ip_configuration->dns1[2], - ip_configuration->dns1[3], - - ip_configuration->dns2[0], - ip_configuration->dns2[1], - ip_configuration->dns2[2], - ip_configuration->dns2[3]); -#endif - } - } - - ipc_gprs_pdp_context_fix(data_call_list, IPC_GPRS_PDP_CONTEXT_GET_DESC_COUNT); - - if (info->aseq == 0xff) - ril_request_unsolicited(RIL_UNSOL_DATA_CALL_LIST_CHANGED, - &data_call_list, sizeof(data_call_list)); - else - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, - &data_call_list, sizeof(data_call_list)); - - for (i = 0; i < IPC_GPRS_PDP_CONTEXT_GET_DESC_COUNT; i++) { - ril_data_call_response_free(data_call_list + i); - } - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_unsol_data_call_list_changed(void) -{ - ipc_fmt_send_get(IPC_GPRS_PDP_CONTEXT, 0xff); -} - -void ril_request_data_call_list(RIL_Token t) -{ - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - ipc_fmt_send_get(IPC_GPRS_PDP_CONTEXT, ril_request_get_id(t)); -} diff --git a/include/plmn_list.h b/include/plmn_list.h index a415d35..8595e43 100644 --- a/include/plmn_list.h +++ b/include/plmn_list.h @@ -1,13 +1,17 @@ -/** - * This list was generated from http://en.wikipedia.org/wiki/Mobile_Network_Code - * - * Date: 26/07/2013 16:36:48 - * Copyright: Wikipedia Contributors, Creative Commons Attribution-ShareAlike License +/* + * 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; @@ -18,12 +22,20 @@ struct plmn_list_entry { struct plmn_list_entry plmn_list[] = { { 1, 1, "TEST", "TEST" }, + // 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 @@ -36,7 +48,7 @@ struct plmn_list_entry plmn_list[] = { { 603, 1, "Mobilis", "Mobilis" }, { 603, 2, "Djezzy", "Djezzy" }, - { 603, 3, "Nedjma", "Nedjma" }, + { 603, 3, "Ooredoo", "Ooredoo" }, // American Samoa (United States of America) - AS @@ -54,13 +66,14 @@ struct plmn_list_entry plmn_list[] = { // Anguilla (United Kingdom) - AI { 365, 10, "Weblinks Limited", "Weblinks Limited" }, - { 365, 840, "Cable & Wireless", "Cable & Wireless" }, + { 365, 840, "LIME", "LIME" }, // Antigua and Barbuda - AG { 344, 30, "APUA", "APUA" }, - { 344, 920, "LIME", "LIME" }, { 344, 50, "Digicel", "Digicel" }, + { 344, 920, "LIME", "LIME" }, + { 344, 930, "AT&T Wireless", "AT&T Wireless" }, // Argentina - AR @@ -74,10 +87,12 @@ struct plmn_list_entry plmn_list[] = { { 722, 340, "Personal", "Personal" }, { 722, 350, "PORT-HABLE", "PORT-HABLE" }, - // Armenia - AM + // Armenia - AM { 283, 1, "Beeline", "Beeline" }, - { 283, 5, "K Telecom CJSC", "K Telecom CJSC" }, + { 283, 4, "Karabakh Telecom", "Karabakh Telecom" }, + { 283, 5, "VivaCell-MTS", "VivaCell-MTS" }, + { 283, 10, "Orange", "Orange" }, // Aruba (Kingdom of the Netherlands) - AW @@ -92,23 +107,31 @@ struct plmn_list_entry plmn_list[] = { { 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, "Victorian Rail Track", "Victorian Rail Track" }, + { 505, 16, "VicTrack", "VicTrack" }, + { 505, 17, "Vidid Wireless Pty. Ltd.", "Vidid Wireless Pty. Ltd." }, { 505, 18, "Pactel", "Pactel" }, - { 505, 19, "Lycamobile Pty Ltd", "Lycamobile Pty Ltd" }, - { 505, 21, "SOUL", "SOUL" }, + { 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, "Advance Communications Technologies Pty. Ltd.", "Advance Communications Technologies 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." }, @@ -120,14 +143,16 @@ struct plmn_list_entry plmn_list[] = { { 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, "A1 Telekom Austria", "A1 Telekom Austria" }, + { 232, 15, "Vectone", "Vectone" }, { 232, 16, "Hutchison Drei Austria", "Hutchison Drei Austria" }, // Azerbaijan - AZ @@ -145,16 +170,18 @@ struct plmn_list_entry plmn_list[] = { { 426, 1, "Batelco", "Batelco" }, { 426, 2, "zain BH", "zain BH" }, - { 426, 4, "VIVA", "VIVA" }, + { 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 Sheba", "Banglalink Sheba" }, + { 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 @@ -169,18 +196,26 @@ struct plmn_list_entry plmn_list[] = { { 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 @@ -189,15 +224,15 @@ struct plmn_list_entry plmn_list[] = { { 616, 2, "Moov", "Moov" }, { 616, 3, "MTN", "MTN" }, { 616, 4, "BBCOM", "BBCOM" }, - { 616, 5, "Glo", "Glo" }, { 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" }, - { 338, 50, "Digicel Bermuda", "Digicel Bermuda" }, - { 310, 59, "Cellular One", "Cellular One" }, // Bhutan - BT @@ -213,7 +248,7 @@ struct plmn_list_entry plmn_list[] = { // Bosnia and Herzegovina - BA { 218, 3, "HT-ERONET", "HT-ERONET" }, - { 218, 5, "m:tel ", "m:tel " }, + { 218, 5, "m:tel", "m:tel" }, { 218, 90, "BH Mobile", "BH Mobile" }, // Botswana - BW @@ -228,8 +263,8 @@ struct plmn_list_entry plmn_list[] = { { 724, 3, "TIM", "TIM" }, { 724, 4, "TIM", "TIM" }, { 724, 5, "Claro BR", "Claro BR" }, - { 724, 6, "Vivo", "Vivo" }, { 724, 55, "Sercomtel", "Sercomtel" }, + { 724, 6, "Vivo", "Vivo" }, { 724, 10, "Vivo", "Vivo" }, { 724, 11, "Vivo", "Vivo" }, { 724, 15, "CTBC Celular", "CTBC Celular" }, @@ -244,6 +279,7 @@ struct plmn_list_entry plmn_list[] = { // 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" }, @@ -257,14 +293,17 @@ struct plmn_list_entry plmn_list[] = { { 284, 1, "M-Tel", "M-Tel" }, { 284, 3, "Vivacom", "Vivacom" }, - { 284, 4, "Undisclosed", "Undisclosed" }, { 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 " }, + { 613, 3, "Telecel Faso", "Telecel Faso" }, // Burundi - BI @@ -278,15 +317,15 @@ struct plmn_list_entry plmn_list[] = { // Cambodia - KH { 456, 1, "Cellcard", "Cellcard" }, - { 456, 2, "Latelz Company Limited", "Latelz Company Limited" }, - { 456, 3, "S Telecom", "S Telecom" }, + { 456, 2, "Smart", "Smart" }, + { 456, 3, "qb", "qb" }, { 456, 4, "qb", "qb" }, - { 456, 5, "Star-Cell", "Star-Cell" }, + { 456, 5, "Latelz Company Limited", "Latelz Company Limited" }, { 456, 6, "Latelz Company Limited", "Latelz Company Limited" }, - { 456, 18, "Cellcard", "Cellcard" }, - { 456, 11, "Excell", "Excell" }, + { 456, 8, "Cellcard", "Cellcard" }, { 456, 9, "Beeline", "Beeline" }, - { 456, 8, "Metfone", "Metfone" }, + { 456, 11, "Excell", "Excell" }, + { 456, 18, "Cellcard", "Cellcard" }, // Cameroon - CM @@ -297,20 +336,28 @@ struct plmn_list_entry plmn_list[] = { { 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, 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, 610, "Bell", "Bell" }, + { 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" }, @@ -318,6 +365,7 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -325,8 +373,15 @@ struct plmn_list_entry plmn_list[] = { { 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 @@ -349,7 +404,7 @@ struct plmn_list_entry plmn_list[] = { { 622, 1, "Airtel", "Airtel" }, { 622, 2, "Tchad Mobile", "Tchad Mobile" }, - { 622, 2, "Tawali ", "Tawali " }, + { 622, 2, "Tawali", "Tawali" }, { 622, 3, "Tigo", "Tigo" }, { 622, 4, "Salam", "Salam" }, @@ -359,10 +414,17 @@ struct plmn_list_entry plmn_list[] = { { 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 @@ -370,10 +432,11 @@ struct plmn_list_entry plmn_list[] = { { 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, 6, "China Unicom", "China Unicom" }, { 460, 7, "China Mobile", "China Mobile" }, - { 460, 20, "China Tietong ", "China Tietong " }, + { 460, 20, "China Tietong", "China Tietong" }, // Christmas Island (Australia) - CX @@ -385,21 +448,25 @@ struct plmn_list_entry plmn_list[] = { { 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, "HURI - SNPT", "HURI - SNPT" }, + { 654, 1, "Comoros Telecom", "Comoros Telecom" }, // Republic of the Congo - CG { 629, 1, "Airtel", "Airtel" }, - { 629, 10, "Libertis Telecom", "Libertis Telecom" }, { 629, 7, "Warid Telecom", "Warid Telecom" }, + { 629, 10, "Libertis Telecom", "Libertis Telecom" }, // Cook Islands (New Zealand) - CK @@ -411,6 +478,7 @@ struct plmn_list_entry plmn_list[] = { { 712, 2, "Kolbi ICE", "Kolbi ICE" }, { 712, 3, "Claro", "Claro" }, { 712, 4, "movistar", "movistar" }, + { 712, 20, "'''full'''móvil", "'''full'''móvil" }, // Croatia - HR @@ -427,6 +495,7 @@ struct plmn_list_entry plmn_list[] = { { 280, 1, "Cytamobile-Vodafone", "Cytamobile-Vodafone" }, { 280, 10, "MTN", "MTN" }, { 280, 20, "PrimeTel", "PrimeTel" }, + { 280, 22, "lemontel", "lemontel" }, // Czech Republic - CZ @@ -436,37 +505,45 @@ struct plmn_list_entry plmn_list[] = { { 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, "Zain", "Zain" }, + { 630, 2, "airtel", "airtel" }, { 630, 4, "Cellco", "Cellco" }, { 630, 5, "Supercell", "Supercell" }, { 630, 10, "Libertis Telecom", "Libertis Telecom" }, - { 630, 86, "CCT", "CCT" }, - { 630, 89, "Tigo DRC", "Tigo DRC" }, - { 630, 992, "Africell", "Africell" }, + { 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, 5, "ApS KBUS", "ApS KBUS" }, + { 238, 4, "NextGen Mobile Ltd", "NextGen Mobile Ltd" }, + { 238, 5, "TetraNet", "TetraNet" }, { 238, 6, "3", "3" }, - { 238, 7, "Barablu Mobile Ltd.", "Barablu Mobile Ltd." }, - { 238, 8, "Nordisk Mobiltelefon", "Nordisk Mobiltelefon" }, - { 238, 9, "Dansk Beredskabskommunikation A/S", "Dansk Beredskabskommunikation A/S" }, + { 238, 7, "Vectone Mobile", "Vectone Mobile" }, + { 238, 8, "Voxbone", "Voxbone" }, + { 238, 9, "SINE", "SINE" }, { 238, 10, "TDC", "TDC" }, - { 238, 11, "Dansk Beredskabskommunikation A/S", "Dansk Beredskabskommunikation A/S" }, - { 238, 12, "Lycamobile Denmark Ltd", "Lycamobile Denmark Ltd" }, + { 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, 30, "Telia", "Telia" }, + { 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 @@ -487,7 +564,7 @@ struct plmn_list_entry plmn_list[] = { // East Timor - TL - { 514, 1, "Telin", "Telin" }, + { 514, 1, "Telin Telkomcel", "Telin Telkomcel" }, { 514, 2, "Timor Telecom", "Timor Telecom" }, { 514, 3, "Viettel Timor-Leste", "Viettel Timor-Leste" }, @@ -526,6 +603,10 @@ struct plmn_list_entry plmn_list[] = { { 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 @@ -535,11 +616,13 @@ struct plmn_list_entry plmn_list[] = { { 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 @@ -547,43 +630,69 @@ struct plmn_list_entry plmn_list[] = { { 244, 4, "AINA", "AINA" }, { 244, 5, "Elisa", "Elisa" }, { 244, 7, "Nokia", "Nokia" }, - { 244, 8, "Unknown", "Unknown" }, - { 244, 9, "Finnet Group / NOKIA OYJ", "Finnet Group / NOKIA OYJ" }, + { 244, 8, "Nokia", "Nokia" }, + { 244, 9, "Finnet Group / Nokia Solutions and Networks", "Finnet Group / Nokia Solutions and Networks" }, { 244, 10, "TDC", "TDC" }, - { 244, 11, "VIRVE", "VIRVE" }, + { 244, 11, "Vectone Mobile", "Vectone Mobile" }, { 244, 12, "DNA", "DNA" }, - { 244, 14, "AMT", "AMT" }, + { 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, 29, "Scnl Truphone", "Scnl Truphone" }, + { 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, 4, "Sisteer ", "Sisteer " }, + { 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 @@ -595,13 +704,14 @@ struct plmn_list_entry plmn_list[] = { { 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 " }, + { 607, 4, "QCell", "QCell" }, // Georgia - GE @@ -610,10 +720,12 @@ struct plmn_list_entry plmn_list[] = { { 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, "T-Mobile", "T-Mobile" }, + { 262, 1, "Telekom", "Telekom" }, { 262, 2, "Vodafone", "Vodafone" }, { 262, 3, "E-Plus", "E-Plus" }, { 262, 4, "Vodafone", "Vodafone" }, @@ -622,19 +734,25 @@ struct plmn_list_entry plmn_list[] = { { 262, 7, "O2", "O2" }, { 262, 8, "O2", "O2" }, { 262, 9, "Vodafone", "Vodafone" }, - { 262, 10, "Arcor AG & Co", "Arcor AG & Co" }, + { 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, 42, "27C3", "27C3" }, + { 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" }, @@ -643,9 +761,10 @@ struct plmn_list_entry plmn_list[] = { { 620, 1, "MTN", "MTN" }, { 620, 2, "Vodafone", "Vodafone" }, { 620, 3, "tiGO", "tiGO" }, - { 620, 4, "Expresso ", "Expresso " }, + { 620, 4, "Expresso", "Expresso" }, { 620, 6, "Airtel", "Airtel" }, - { 620, 7, "Globacom (Zain)", "Globacom (Zain)" }, + { 620, 7, "Globacom", "Globacom" }, + { 620, 11, "Netafrique Dot Com Ltd", "Netafrique Dot Com Ltd" }, // Gibraltar (United Kingdom) - GI @@ -656,7 +775,12 @@ struct plmn_list_entry plmn_list[] = { // 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" }, @@ -682,21 +806,21 @@ struct plmn_list_entry plmn_list[] = { { 310, 32, "IT&E Wireless", "IT&E Wireless" }, { 310, 33, "Guam Telephone Authority", "Guam Telephone Authority" }, { 310, 140, "mPulse", "mPulse" }, - { 310, 370, "docomo", "docomo" }, { 311, 250, "i CAN_GSM", "i CAN_GSM" }, - { 310, 470, "docomo", "docomo" }, + { 310, 370, "Docomo", "Docomo" }, + { 310, 470, "Docomo", "Docomo" }, // Guatemala - GT { 704, 1, "Claro", "Claro" }, - { 704, 201, "Tigo", "Tigo" }, + { 704, 2, "Tigo", "Tigo" }, { 704, 3, "movistar", "movistar" }, // Guernsey (United Kingdom) - GG - { 234, 55, "Sure Mobile", "Sure Mobile" }, - { 234, 50, "Wave Telecom", "Wave Telecom" }, { 234, 3, "Airtel Vodafone", "Airtel Vodafone" }, + { 234, 50, "Wave Telecom", "Wave Telecom" }, + { 234, 55, "Sure Mobile", "Sure Mobile" }, // Guinea - GN @@ -708,7 +832,8 @@ struct plmn_list_entry plmn_list[] = { // Guinea-Bissau - GW - { 632, 2, "Areeba", "Areeba" }, + { 632, 1, "Guinetel", "Guinetel" }, + { 632, 2, "MTN Areeba", "MTN Areeba" }, { 632, 3, "Orange", "Orange" }, { 632, 7, "Guinetel", "Guinetel" }, @@ -721,20 +846,20 @@ struct plmn_list_entry plmn_list[] = { { 372, 1, "Voila", "Voila" }, { 372, 2, "Digicel", "Digicel" }, - { 372, 3, "Telecommunication S.A.", "Telecommunication S.A." }, + { 372, 3, "Natcom", "Natcom" }, // Honduras - HN { 708, 1, "Claro", "Claro" }, { 708, 2, "Tigo", "Tigo" }, { 708, 30, "Hondutel", "Hondutel" }, - { 708, 40, "DIGICEL ", "DIGICEL " }, + { 708, 40, "Digicel", "Digicel" }, // Hong Kong - HK { 454, 1, "CITIC Telecom 1616", "CITIC Telecom 1616" }, - { 454, 2, "CSL Limited ", "CSL Limited " }, - { 454, 3, "3 (3G) ", "3 (3G) " }, + { 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" }, @@ -749,17 +874,19 @@ struct plmn_list_entry plmn_list[] = { { 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)", "PCCW Mobile (3G)" }, + { 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 @@ -862,31 +989,12 @@ struct plmn_list_entry plmn_list[] = { { 404, 97, "AirTel", "AirTel" }, { 404, 98, "AirTel", "AirTel" }, { 405, 1, "Reliance", "Reliance" }, - { 405, 3, "Reliance", "Reliance" }, - { 405, 4, "Reliance", "Reliance" }, - { 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, 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" }, @@ -897,6 +1005,7 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -904,6 +1013,24 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -911,6 +1038,7 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -942,6 +1070,7 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -951,27 +1080,27 @@ struct plmn_list_entry plmn_list[] = { { 405, 851, "IDEA", "IDEA" }, { 405, 852, "IDEA", "IDEA" }, { 405, 853, "IDEA", "IDEA" }, - { 405, 854, "Loop Mobile", "Loop Mobile" }, - { 405, 855, "Loop Mobile", "Loop Mobile" }, - { 405, 856, "Loop Mobile", "Loop Mobile" }, - { 405, 857, "Loop Mobile", "Loop Mobile" }, - { 405, 858, "Loop Mobile", "Loop Mobile" }, - { 405, 859, "Loop Mobile", "Loop Mobile" }, - { 405, 860, "Loop Mobile", "Loop Mobile" }, - { 405, 861, "Loop Mobile", "Loop Mobile" }, - { 405, 862, "Loop Mobile", "Loop Mobile" }, - { 405, 863, "Loop Mobile", "Loop Mobile" }, - { 405, 864, "Loop Mobile", "Loop Mobile" }, - { 405, 865, "Loop Mobile", "Loop Mobile" }, - { 405, 866, "Loop Mobile", "Loop Mobile" }, - { 405, 867, "Loop Mobile", "Loop Mobile" }, - { 405, 868, "Loop Mobile", "Loop Mobile" }, - { 405, 869, "Loop Mobile", "Loop Mobile" }, - { 405, 870, "Loop Mobile", "Loop Mobile" }, - { 405, 871, "Loop Mobile", "Loop Mobile" }, - { 405, 872, "Loop Mobile", "Loop Mobile" }, - { 405, 873, "Loop Mobile", "Loop Mobile" }, - { 405, 874, "Loop Mobile", "Loop Mobile" }, + { 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" }, @@ -992,7 +1121,7 @@ struct plmn_list_entry plmn_list[] = { { 510, 3, "StarOne", "StarOne" }, { 510, 7, "TelkomFlexi", "TelkomFlexi" }, { 510, 8, "AXIS", "AXIS" }, - { 510, 9, "SMART", "SMART" }, + { 510, 9, "SMARTFREN", "SMARTFREN" }, { 510, 10, "Telkomsel", "Telkomsel" }, { 510, 11, "XL", "XL" }, { 510, 20, "TELKOMMobile", "TELKOMMobile" }, @@ -1002,6 +1131,7 @@ struct plmn_list_entry plmn_list[] = { { 510, 89, "3", "3" }, { 510, 99, "Esia", "Esia" }, { 510, 995, "Komselindo", "Komselindo" }, + { 510, 996, "Komselindo", "Komselindo" }, // Iran - IR @@ -1039,8 +1169,8 @@ struct plmn_list_entry plmn_list[] = { // Isle of Man (United Kingdom) - IM - { 234, 58, "Pronto GSM", "Pronto GSM" }, { 234, 9, "Sure Mobile", "Sure Mobile" }, + { 234, 58, "Pronto GSM", "Pronto GSM" }, // Israel - IL @@ -1049,10 +1179,17 @@ struct plmn_list_entry plmn_list[] = { { 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 @@ -1063,6 +1200,7 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -1082,6 +1220,7 @@ struct plmn_list_entry plmn_list[] = { { 338, 20, "LIME", "LIME" }, { 338, 50, "Digicel", "Digicel" }, + { 338, 110, "LIME", "LIME" }, { 338, 180, "LIME", "LIME" }, // Japan - JP @@ -1184,14 +1323,14 @@ struct plmn_list_entry plmn_list[] = { // Jersey (United Kingdom) - JE + { 234, 3, "Airtel Vodafone", "Airtel Vodafone" }, { 234, 50, "JT", "JT" }, { 234, 55, "Sure Mobile", "Sure Mobile" }, - { 234, 3, "Airtel Vodafone", "Airtel Vodafone" }, // Jordan - JO { 416, 1, "zain JO", "zain JO" }, - { 416, 74, "XPress Telecom", "XPress Telecom" }, + { 416, 2, "XPress Telecom", "XPress Telecom" }, { 416, 3, "Umniah", "Umniah" }, { 416, 77, "Orange", "Orange" }, @@ -1201,19 +1340,18 @@ struct plmn_list_entry plmn_list[] = { { 401, 2, "Kcell", "Kcell" }, { 401, 7, "Dalacom", "Dalacom" }, { 401, 8, "Kazakhtelecom", "Kazakhtelecom" }, - { 401, 10, "Dontelecom", "Dontelecom" }, { 401, 77, "Tele2.kz", "Tele2.kz" }, // Kenya - KE { 639, 2, "Safaricom", "Safaricom" }, { 639, 3, "Airtel", "Airtel" }, - { 639, 7, "Orange Kenya", "Orange Kenya" }, { 639, 5, "yu", "yu" }, + { 639, 7, "Orange Kenya", "Orange Kenya" }, // Kiribati - KI - { 545, 1, "Kiribati - Frigate Net", "Kiribati - Frigate Net" }, + { 545, 1, "Kiribati - TSKL", "Kiribati - TSKL" }, { 545, 9, "Kiribati - Frigate Net", "Kiribati - Frigate Net" }, // North Korea - KP @@ -1231,12 +1369,12 @@ struct plmn_list_entry plmn_list[] = { { 450, 8, "olleh", "olleh" }, { 450, 11, "SKTelecom", "SKTelecom" }, - // Kosovo - RKS + // Kosovo - XK { 212, 1, "Vala", "Vala" }, + { 212, 1, "Z Mobile", "Z Mobile" }, { 293, 41, "IPKO", "IPKO" }, { 293, 41, "D3 Mobile", "D3 Mobile" }, - { 212, 1, "Z Mobile", "Z Mobile" }, // Kuwait - KW @@ -1263,6 +1401,7 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -1300,21 +1439,24 @@ struct plmn_list_entry plmn_list[] = { { 295, 1, "Swisscom", "Swisscom" }, { 295, 2, "Orange", "Orange" }, { 295, 5, "FL1", "FL1" }, - { 295, 77, "Alpmobil", "Alpmobil" }, { 295, 6, "Cubic Telecom", "Cubic Telecom" }, + { 295, 77, "Alpmobil", "Alpmobil" }, // Lithuania - LT { 246, 1, "Omnitel", "Omnitel" }, - { 246, 2, "BITE", "BITE" }, + { 246, 2, "BITĖ", "BITĖ" }, { 246, 3, "Tele 2", "Tele 2" }, { 246, 5, "LitRail", "LitRail" }, { 246, 6, "Mediafon", "Mediafon" }, // Luxembourg - LU - { 270, 1, "LuxGSM", "LuxGSM" }, + { 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 @@ -1324,6 +1466,7 @@ struct plmn_list_entry plmn_list[] = { { 455, 3, "3", "3" }, { 455, 4, "CTM", "CTM" }, { 455, 5, "3", "3" }, + { 455, 6, "SmarTone", "SmarTone" }, // Macedonia - MK @@ -1335,7 +1478,7 @@ struct plmn_list_entry plmn_list[] = { { 646, 1, "Airtel", "Airtel" }, { 646, 2, "Orange", "Orange" }, - { 646, 3, "Sacel ", "Sacel " }, + { 646, 3, "Sacel", "Sacel" }, { 646, 4, "Telma", "Telma" }, // Malawi - MW @@ -1351,20 +1494,22 @@ struct plmn_list_entry plmn_list[] = { { 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, 150, "Tune Talk", "Tune Talk" }, - { 502, 151, "Baraka Telecom Sdn Bhd (MVNE)", "Baraka Telecom Sdn Bhd (MVNE)" }, - { 502, 152, "Yes", "Yes" }, + { 502, 12, "Kartu As", "Kartu As" }, // Maldives - MV { 472, 1, "Dhiraagu", "Dhiraagu" }, - { 472, 2, "Wataniya", "Wataniya" }, + { 472, 2, "Ooredoo", "Ooredoo" }, // Mali - ML @@ -1379,7 +1524,7 @@ struct plmn_list_entry plmn_list[] = { // Marshall Islands - MH - { 551, 1, "Marshall Islands National Telecommunications Authority (MINTA) ", "Marshall Islands National Telecommunications Authority (MINTA) " }, + { 551, 1, "Marshall Islands National Telecommunications Authority (MINTA)", "Marshall Islands National Telecommunications Authority (MINTA)" }, // Martinique (France) - MQ @@ -1407,6 +1552,7 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -1462,12 +1608,14 @@ struct plmn_list_entry plmn_list[] = { // 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, "Leo", "Leo" }, + { 649, 3, "TN Mobile", "TN Mobile" }, // Nauru - NR @@ -1482,20 +1630,21 @@ struct plmn_list_entry plmn_list[] = { // Netherlands (Kingdom of the Netherlands) - NL - { 204, 1, "VastMobiel B.V.", "VastMobiel B.V." }, + { 204, 1, "RadioAccess Network Services BV", "RadioAccess Network Services BV" }, { 204, 2, "Tele2", "Tele2" }, { 204, 3, "Voiceworks", "Voiceworks" }, - { 204, 4, "Vodafone Libertel B.V.", "Vodafone Libertel B.V." }, + { 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, 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 B.V.", "Ziggo 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." }, @@ -1509,17 +1658,23 @@ struct plmn_list_entry plmn_list[] = { { 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, "Unify Group Holding B.V.", "Unify Group Holding 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." }, - // Netherlands Antilles (Kingdom of the Netherlands) - AN + // Former Netherlands Antilles (Kingdom of the Netherlands) - AN { 362, 51, "Telcell", "Telcell" }, { 362, 69, "Digicel", "Digicel" }, { 362, 91, "UTS", "UTS" }, - { 362, 95, "MIO", "MIO" }, { 362, 94, "Bayòs", "Bayòs" }, + { 362, 95, "MIO", "MIO" }, // New Caledonia (France) - NC @@ -1532,8 +1687,8 @@ struct plmn_list_entry plmn_list[] = { { 530, 3, "Woosh", "Woosh" }, { 530, 4, "TelstraClear", "TelstraClear" }, { 530, 5, "XT Mobile Network", "XT Mobile Network" }, - { 530, 24, "2degrees", "2degrees" }, { 530, 6, "Skinny", "Skinny" }, + { 530, 24, "2degrees", "2degrees" }, // Nicaragua - NI @@ -1577,10 +1732,14 @@ struct plmn_list_entry plmn_list[] = { { 242, 5, "Network Norway", "Network Norway" }, { 242, 6, "Ice", "Ice" }, { 242, 7, "Ventelo", "Ventelo" }, - { 242, 8, "TDC ", "TDC " }, + { 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 @@ -1592,15 +1751,16 @@ struct plmn_list_entry plmn_list[] = { { 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", "Warid" }, + { 410, 7, "Warid Pakistan", "Warid Pakistan" }, // Palau - PW { 552, 1, "PNCC", "PNCC" }, { 552, 80, "Palau Mobile", "Palau Mobile" }, - // State of Palestine - PS + // Palestine, State of - PS { 425, 5, "Jawwal", "Jawwal" }, { 425, 6, "Wataniya", "Wataniya" }, @@ -1609,12 +1769,12 @@ struct plmn_list_entry plmn_list[] = { { 714, 1, "Cable & Wireless", "Cable & Wireless" }, { 714, 2, "movistar", "movistar" }, - { 714, 4, "Digicel", "Digicel" }, { 714, 3, "Claro", "Claro" }, + { 714, 4, "Digicel", "Digicel" }, // Papua New Guinea - PG - { 537, 1, "BeMobile", "BeMobile" }, + { 537, 1, "bmobile", "bmobile" }, { 537, 3, "Digicel", "Digicel" }, // Paraguay - PY @@ -1629,7 +1789,7 @@ struct plmn_list_entry plmn_list[] = { { 716, 6, "Movistar", "Movistar" }, { 716, 7, "NEXTEL", "NEXTEL" }, - { 716, 10, "Claro(TIM)", "Claro(TIM)" }, + { 716, 10, "Claro (TIM)", "Claro (TIM)" }, { 716, 15, "Viettel Mobile", "Viettel Mobile" }, { 716, 17, "NEXTEL", "NEXTEL" }, @@ -1641,6 +1801,7 @@ struct plmn_list_entry plmn_list[] = { { 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 @@ -1665,6 +1826,7 @@ struct plmn_list_entry plmn_list[] = { { 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." }, @@ -1672,24 +1834,26 @@ struct plmn_list_entry plmn_list[] = { { 268, 1, "Vodafone", "Vodafone" }, { 268, 3, "Optimus", "Optimus" }, - { 268, 7, "Vectonemobile - Delightmobile", "Vectonemobile - Delightmobile" }, { 268, 4, "LycaMobile", "LycaMobile" }, { 268, 6, "TMN", "TMN" }, + { 268, 7, "Vectonemobile - Delightmobile", "Vectonemobile - Delightmobile" }, { 268, 21, "Zapp", "Zapp" }, // Puerto Rico - PR - { 330, 110, "Claro", "Claro" }, - { 330, 120, "Open Mobile", "Open Mobile" }, + { 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" }, @@ -1702,6 +1866,7 @@ struct plmn_list_entry plmn_list[] = { { 226, 5, "Digi.Mobil", "Digi.Mobil" }, { 226, 6, "Cosmote/Zapp", "Cosmote/Zapp" }, { 226, 10, "Orange", "Orange" }, + { 226, 15, "Idilis", "Idilis" }, // Russian Federation - RU @@ -1718,9 +1883,11 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -1741,6 +1908,7 @@ struct plmn_list_entry plmn_list[] = { { 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 @@ -1750,7 +1918,7 @@ struct plmn_list_entry plmn_list[] = { // Saint Lucia - LC - { 358, 358, "| 358 || 050 ||Unknown", "| 358 || 050 ||Unknown" }, + { 358, 50, "Digicel", "Digicel" }, { 358, 110, "Cable & Wireless", "Cable & Wireless" }, // Saint Pierre and Miquelon (France) - PM @@ -1789,6 +1957,7 @@ struct plmn_list_entry plmn_list[] = { { 608, 1, "Orange", "Orange" }, { 608, 2, "Tigo", "Tigo" }, { 608, 3, "Expresso", "Expresso" }, + { 608, 4, "CSU-SA", "CSU-SA" }, // Serbia - RS @@ -1806,10 +1975,10 @@ struct plmn_list_entry plmn_list[] = { // Sierra Leone - SL { 619, 1, "Airtel", "Airtel" }, - { 619, 2, "Tigo", "Tigo" }, { 619, 3, "Africell", "Africell" }, { 619, 4, "Comium", "Comium" }, { 619, 5, "Africell", "Africell" }, + { 619, 6, "SierraTel", "SierraTel" }, { 619, 25, "Mobitel", "Mobitel" }, // Singapore - SG @@ -1825,16 +1994,18 @@ struct plmn_list_entry plmn_list[] = { // Slovakia - SK { 231, 1, "Orange", "Orange" }, - { 231, 2, "T-Mobile", "T-Mobile" }, + { 231, 2, "Telekom", "Telekom" }, { 231, 3, "Unient Communications", "Unient Communications" }, { 231, 4, "T-Mobile", "T-Mobile" }, - { 231, 6, "O2 ", "O2 " }, + { 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" }, @@ -1845,11 +2016,11 @@ struct plmn_list_entry plmn_list[] = { // Somalia - SO - { 637, 4, "SomaCyber", "SomaCyber" }, { 637, 1, "Telesom", "Telesom" }, + { 637, 4, "SomaCyber", "SomaCyber" }, { 637, 4, "Somafone", "Somafone" }, { 637, 10, "Nationlink", "Nationlink" }, - { 637, 25, "Hormuud", "Hormuud" }, + { 637, 50, "Hormuud", "Hormuud" }, { 637, 30, "Golis", "Golis" }, { 637, 57, "Unittel", "Unittel" }, { 637, 60, "Nationlink Telecom", "Nationlink Telecom" }, @@ -1865,12 +2036,15 @@ struct plmn_list_entry plmn_list[] = { { 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 @@ -1900,7 +2074,12 @@ struct plmn_list_entry plmn_list[] = { { 214, 22, "DigiMobil", "DigiMobil" }, { 214, 23, "Barablu", "Barablu" }, { 214, 24, "Eroski", "Eroski" }, - { 214, 25, "LycaMobile", "LycaMobile" }, + { 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 @@ -1914,6 +2093,7 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -1931,7 +2111,7 @@ struct plmn_list_entry plmn_list[] = { { 240, 1, "Telia", "Telia" }, { 240, 2, "3", "3" }, - { 240, 3, "Ice.net", "Ice.net" }, + { 240, 3, "Net 1", "Net 1" }, { 240, 4, "SWEDEN", "SWEDEN" }, { 240, 5, "Sweden 3G", "Sweden 3G" }, { 240, 6, "Telenor", "Telenor" }, @@ -1939,20 +2119,40 @@ struct plmn_list_entry plmn_list[] = { { 240, 8, "Telenor", "Telenor" }, { 240, 9, "djuice", "djuice" }, { 240, 10, "Spring Mobil", "Spring Mobil" }, - { 240, 11, "Lindholmen Science Park", "Lindholmen Science Park" }, - { 240, 12, "Lycamobile Sweden ", "Lycamobile Sweden " }, - { 240, 13, "Ventelo Sverige", "Ventelo Sverige" }, - { 240, 14, "TDC Mobil", "TDC Mobil" }, - { 240, 15, "Wireless Maingate Nordic", "Wireless Maingate Nordic" }, - { 240, 16, "42IT", "42IT" }, - { 240, 17, "Götalandsnätet", "Götalandsnätet" }, - { 240, 20, "Wireless Maingate Message Services", "Wireless Maingate Message Services" }, + { 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, "DigiTelMobile", "DigiTelMobile" }, - { 240, 26, "Beepsend", "Beepsend" }, + { 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, 41, "Shyam Telecom UK Ltd", "Shyam Telecom UK Ltd" }, + { 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 @@ -1970,6 +2170,7 @@ struct plmn_list_entry plmn_list[] = { { 228, 52, "Barablu", "Barablu" }, { 228, 53, "UPC", "UPC" }, { 228, 54, "Lyca Mobile", "Lyca Mobile" }, + { 228, 99, "Swisscom", "Swisscom" }, // Syria - SY @@ -1980,9 +2181,9 @@ struct plmn_list_entry plmn_list[] = { { 466, 1, "FarEasTone", "FarEasTone" }, { 466, 5, "APTG", "APTG" }, - { 466, 6, "Tuntex", "Tuntex" }, + { 466, 6, "FarEasTone", "FarEasTone" }, { 466, 11, "Chunghwa LDM", "Chunghwa LDM" }, - { 466, 88, "KG Telecom", "KG Telecom" }, + { 466, 88, "FarEasTone", "FarEasTone" }, { 466, 89, "VIBO", "VIBO" }, { 466, 92, "Chungwa", "Chungwa" }, { 466, 93, "MobiTai", "MobiTai" }, @@ -1993,9 +2194,9 @@ struct plmn_list_entry plmn_list[] = { { 436, 1, "Tcell", "Tcell" }, { 436, 2, "Tcell", "Tcell" }, - { 436, 3, "Megafon", "Megafon" }, + { 436, 3, "Megafon Tajikistan", "Megafon Tajikistan" }, { 436, 4, "Babilon-M", "Babilon-M" }, - { 436, 5, "Tacom", "Tacom" }, + { 436, 5, "Beeline", "Beeline" }, { 436, 12, "Tcell", "Tcell" }, // Tanzania - TZ @@ -2012,17 +2213,18 @@ struct plmn_list_entry plmn_list[] = { // Thailand - TH - { 520, 1, "AIS ", "AIS " }, + { 520, 1, "AIS", "AIS" }, { 520, 2, "CAT CDMA", "CAT CDMA" }, { 520, 3, "AIS 3G", "AIS 3G" }, - { 520, 4, "True Move H 4G LTE", "True Move H 4G LTE" }, - { 520, 5, "dtac 3G", "dtac 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, 99, "True Move", "True Move" }, { 520, 25, "WE PCT", "WE PCT" }, + { 520, 47, "Telephone Organization of Thailand (TOT)", "Telephone Organization of Thailand (TOT)" }, + { 520, 99, "truemove", "truemove" }, // Togo - TG @@ -2055,7 +2257,7 @@ struct plmn_list_entry plmn_list[] = { // Turkmenistan - TM - { 438, 1, "MTS (BARASH Communication) ", "MTS (BARASH Communication) " }, + { 438, 1, "MTS (BARASH Communication)", "MTS (BARASH Communication)" }, { 438, 2, "TM-Cell", "TM-Cell" }, // Turks and Caicos Islands - TC @@ -2072,9 +2274,12 @@ struct plmn_list_entry plmn_list[] = { { 641, 1, "Airtel", "Airtel" }, { 641, 10, "MTN", "MTN" }, - { 641, 11, "UTL", "UTL" }, + { 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 @@ -2111,31 +2316,41 @@ struct plmn_list_entry plmn_list[] = { { 234, 13, "Railtrack", "Railtrack" }, { 234, 14, "Hay Systems Ltd", "Hay Systems Ltd" }, { 234, 15, "Vodafone UK", "Vodafone UK" }, - { 234, 16, "Talk Talk (Opal Tel Ltd)", "Talk Talk (Opal Tel Ltd)" }, + { 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, 27, "United Kingdom of Great Britain and Northern Ireland", "United Kingdom of Great Britain and Northern Ireland" }, - { 234, 30, "T-Mobile (UK)", "T-Mobile (UK)" }, + { 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, "Cable and Wireless Isle of Man Limited", "Cable and Wireless Isle of Man 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 Limited", "UK Broadband Limited" }, + { 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" }, @@ -2144,13 +2359,9 @@ struct plmn_list_entry plmn_list[] = { // United States of America - US - { 310, 53, "Virgin Mobile US", "Virgin Mobile US" }, - { 310, 54, "Alltel US", "Alltel US" }, - { 310, 66, "U.S. Cellular", "U.S. Cellular" }, { 310, 4, "Verizon", "Verizon" }, { 310, 5, "Verizon", "Verizon" }, { 310, 10, "MCI", "MCI" }, - { 310, 12, "Verizon", "Verizon" }, { 310, 13, "MobileTel", "MobileTel" }, { 310, 14, "Testing", "Testing" }, { 310, 16, "Cricket Communications", "Cricket Communications" }, @@ -2161,11 +2372,14 @@ struct plmn_list_entry plmn_list[] = { { 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, 100, "Plateau Wireless", "Plateau Wireless" }, { 310, 110, "PTI Pacifica", "PTI Pacifica" }, { 310, 120, "Sprint", "Sprint" }, { 310, 150, "AT&T", "AT&T" }, @@ -2243,6 +2457,7 @@ struct plmn_list_entry plmn_list[] = { { 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" }, @@ -2267,9 +2482,13 @@ struct plmn_list_entry plmn_list[] = { { 311, 330, "Bug Tussel Wireless", "Bug Tussel Wireless" }, { 311, 480, "Verizon", "Verizon" }, { 311, 481, "Verizon", "Verizon" }, - { 311, 660, "metroPCS ", "metroPCS " }, + { 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" }, @@ -2289,18 +2508,20 @@ struct plmn_list_entry plmn_list[] = { { 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, 1, "Digitel", "Digitel" }, { 734, 2, "Digitel GSM", "Digitel GSM" }, { 734, 3, "Digitel", "Digitel" }, { 734, 4, "movistar", "movistar" }, @@ -2308,14 +2529,14 @@ struct plmn_list_entry plmn_list[] = { // Vietnam - VN - { 452, 1, "MobiFone ", "MobiFone " }, + { 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, 8, "3G EVNTelecom", "3G EVNTelecom" }, { 452, 7, "G-Mobile", "G-Mobile" }, + { 452, 8, "3G EVNTelecom", "3G EVNTelecom" }, // Yemen - YE @@ -2371,7 +2592,11 @@ struct plmn_list_entry plmn_list[] = { { 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 index 26e9616..0a17068 100755 --- a/include/plmn_list.sh +++ b/include/plmn_list.sh @@ -1,22 +1,26 @@ #!/bin/sh # -# Copyright 2012 Paul Kocialkowski, GPLv3+ +# 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. +# 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 http://en.wikipedia.org/wiki/Mobile_Network_Code" -echo " * " +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 Attribution-ShareAlike License" +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;" @@ -26,7 +30,7 @@ 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" | tail -n +2 | sed "s|.*=== \(.*\) ===.*|// \1|g" | grep -v "|-" | while read line +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 @@ -37,7 +41,7 @@ do if [ ! "$test" = "" ] then - echo "\n\t$line\n" | sed -e "s#[^|]*|\(.*\)#// \1#g" -e "s/^ //g" -e "s/ $//g" + echo "\n\t$line\n" | sed -e "s#[^|]*|\(.*\)#// \1#g" -e "s/^ //g" -e "s/ $//g" -e "s/ / /g" continue fi @@ -48,10 +52,10 @@ do continue fi - mcc=$( echo "$line" | sed -e "s#[^|]*|[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\).*#\1#g" -e "s/^ //g" -e "s/ $//g" -e "s/[^1-9]*\([0-9]*\).*/\1/g") - mnc=$( echo "$line" | sed -e "s#[^|]*|[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\).*#\2#g" -e "s/^ //g" -e "s/ $//g" -e "s/[^1-9]*\([0-9]*\).*/\1/g") - brand=$( echo "$line" | sed -e "s#[^|]*|[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\).*#\3#g" -e "s/^ //g" -e "s/ $//g" ) - operator=$( echo "$line" | sed -e "s#[^|]*|[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\)[ ]*||[ ]*\([^|]*\).*#\4#g" -e "s/^ //g" -e "s/ $//g" ) + 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 @@ -78,4 +82,7 @@ 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/ril_oem.h b/include/ril_oem.h new file mode 100644 index 0000000..c38db00 --- /dev/null +++ b/include/ril_oem.h @@ -0,0 +1,52 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr> + * + * Samsung-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. + * + * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _RIL_OEM_H_ +#define _RIL_OEM_H_ + +#include <stdlib.h> + +#define RIL_OEM_HOOK_TAG_SVC 1 + +#define RIL_OEM_COMMAND_SVC_ENTER_MODE 1 +#define RIL_OEM_COMMAND_SVC_END_MODE 2 +#define RIL_OEM_COMMAND_SVC_KEY 3 + +typedef struct { + unsigned char tag; + unsigned char command; + unsigned short length; +} RIL_OEMHookHeader; + +typedef struct { + unsigned char mode; + unsigned char type; + unsigned char query; +} RIL_OEMHookSvcEnterMode; + +typedef struct { + unsigned char mode; +} RIL_OEMHookSvcEndMode; + +typedef struct { + unsigned char key; + unsigned char query; +} RIL_OEMHookSvcKey; + +#endif diff --git a/include/samsung-ril-socket.h b/include/samsung-ril-socket.h index d231e62..9e919d1 100644 --- a/include/samsung-ril-socket.h +++ b/include/samsung-ril-socket.h @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@oaulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,40 +17,36 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ -/* Samsung RIL Socket protocol defines */ - #ifndef _SAMSUNG_RIL_SOCKET_H_ #define _SAMSUNG_RIL_SOCKET_H_ -#define SRS_COMMAND(f) ((f->group << 8) | f->index) -#define SRS_GROUP(m) (m >> 8) -#define SRS_INDEX(m) (m & 0xff) +#include <stdlib.h> -#define SRS_SOCKET_NAME "samsung-ril-socket" -#define SRS_DATA_MAX_SIZE 0x1000 +/* + * Groups + */ -#define SRS_CONTROL 0x01 -#define SRS_CONTROL_PING 0x0101 +#define SRS_GROUP_CONTROL 0x01 +#define SRS_GROUP_SND 0x02 -#define SRS_SND 0x02 -#define SRS_SND_SET_CALL_VOLUME 0x0201 -#define SRS_SND_SET_CALL_AUDIO_PATH 0x0202 -#define SRS_SND_SET_CALL_CLOCK_SYNC 0x0203 +/* + * Commands + */ -#define SRS_CONTROL_CAFFE 0xCAFFE +#define SRS_CONTROL_PING 0x0101 -struct srs_header { - unsigned int length; - unsigned char group; - unsigned char index; -} __attribute__((__packed__)); +#define SRS_SND_SET_CALL_VOLUME 0x0201 +#define SRS_SND_SET_CALL_AUDIO_PATH 0x0202 +#define SRS_SND_SET_CALL_CLOCK_SYNC 0x0203 -struct srs_message { - unsigned short command; - int length; - void *data; -}; +/* + * Values + */ + +#define SRS_SOCKET_NAME "samsung-ril-socket" +#define SRS_BUFFER_LENGTH 0x1000 +#define SRS_CONTROL_CAFFE 0xCAFFE enum srs_snd_type { SRS_SND_TYPE_VOICE, @@ -73,21 +69,45 @@ enum srs_snd_clock { SND_CLOCK_START }; -struct srs_snd_call_volume { +/* + * Macros + */ + +#define SRS_COMMAND(group, index) ((group << 8) | index) +#define SRS_GROUP(command) (command >> 8) +#define SRS_INDEX(command) (command & 0xff) + +/* + * Structures + */ + +struct srs_message { + unsigned short command; + void *data; + size_t size; +}; + +struct srs_header { + unsigned int length; + unsigned char group; + unsigned char index; +} __attribute__((__packed__)); + +struct srs_control_ping_data { + unsigned int caffe; +} __attribute__((__packed__)); + +struct srs_snd_call_volume_data { enum srs_snd_type type; int volume; } __attribute__((__packed__)); -struct srs_snd_call_audio_path { +struct srs_snd_call_audio_path_data { enum srs_snd_path path; } __attribute__((__packed__)); -struct srs_snd_call_clock_sync { +struct srs_snd_call_clock_sync_data { unsigned char sync; } __attribute__((__packed__)); -struct srs_control_ping { - int caffe; -} __attribute__((__packed__)); - #endif diff --git a/include/sim.h b/include/sim.h index dc16808..d3ec95c 100644 --- a/include/sim.h +++ b/include/sim.h @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,22 +20,36 @@ #ifndef _SIM_H_ #define _SIM_H_ -// Values from TS 11.11 -#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 +#include <stdlib.h> -#define SIM_FILE_STRUCTURE_TRANSPARENT 0x00 -#define SIM_FILE_STRUCTURE_LINEAR_FIXED 0x01 -#define SIM_FILE_STRUCTURE_CYCLIC 0x03 +#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_TYPE_RFU 0x00 -#define SIM_FILE_TYPE_MF 0x01 -#define SIM_FILE_TYPE_DF 0x02 -#define SIM_FILE_TYPE_EF 0x04 +#define SIM_FILE_STRUCTURE_TRANSPARENT 0x00 +#define SIM_FILE_STRUCTURE_LINEAR_FIXED 0x01 +#define SIM_FILE_STRUCTURE_CYCLIC 0x03 + +#define SIM_FILE_TYPE_RFU 0x00 +#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 char file_size[2]; + unsigned char file_id[2]; + 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__)); struct sim_file_id { unsigned short file_id; @@ -85,19 +99,7 @@ struct sim_file_id sim_file_ids[] = { { 0x7F20, SIM_FILE_TYPE_DF }, }; -int sim_file_ids_count = sizeof(sim_file_ids) / sizeof(sim_file_ids[0]); - -struct sim_file_response { - unsigned char rfu12[2]; - unsigned char file_size[2]; - unsigned char file_id[2]; - 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__)); +unsigned int sim_file_ids_count = sizeof(sim_file_ids) / + sizeof(struct sim_file_id); #endif @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,364 +18,1092 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdlib.h> +#include <sys/eventfd.h> + #define LOG_TAG "RIL-IPC" #include <utils/Log.h> +#include <hardware_legacy/power.h> -#include "samsung-ril.h" +#include <samsung-ril.h> +#include <utils.h> /* - * IPC shared + * Utils */ void ipc_log_handler(void *log_data, const char *message) { - RIL_LOGD("ipc: %s", message); + RIL_LOGD("%s", message); } /* * IPC FMT */ -void ipc_fmt_send(const unsigned short command, const char type, unsigned char *data, const int length, unsigned char mseq) -{ - struct ipc_client *ipc_client; - - if (ril_data.ipc_fmt_client == NULL || ril_data.ipc_fmt_client->data == NULL) - return; - - ipc_client = (struct ipc_client *) ril_data.ipc_fmt_client->data; - - RIL_CLIENT_LOCK(ril_data.ipc_fmt_client); - ipc_client_send(ipc_client, command, type, data, length, mseq); - RIL_CLIENT_UNLOCK(ril_data.ipc_fmt_client); -} - -int ipc_fmt_read_loop(struct ril_client *client) +int ipc_fmt_send(unsigned char mseq, unsigned short command, unsigned char type, + const void *data, size_t size) { - struct ipc_client *ipc_client; - struct ipc_message_info info; - + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; int rc; + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); if (client == NULL || client->data == NULL) - return -EINVAL; + return -1; - ipc_client = (struct ipc_client *) client->data; + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + if (ipc_fmt_data->ipc_client == NULL || ipc_fmt_data->event_fd < 0) + return -1; - while (1) { - rc = ipc_client_poll(ipc_client, NULL); - if (rc < 0) { - RIL_LOGE("IPC FMT client poll failed, aborting"); - goto error; - } - - memset(&info, 0, sizeof(info)); - - RIL_CLIENT_LOCK(client); - if (ipc_client_recv(ipc_client, &info) < 0) { - RIL_CLIENT_UNLOCK(client); - RIL_LOGE("IPC FMT recv failed, aborting"); - goto error; - } - RIL_CLIENT_UNLOCK(client); + if (!client->available) { + RIL_LOGE("%s client is not available", client->name); + return -1; + } - ipc_fmt_dispatch(&info); + RIL_CLIENT_LOCK(client); + acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING); - ipc_client_response_free(ipc_client, &info); + rc = ipc_client_send(ipc_fmt_data->ipc_client, mseq, command, type, data, size); + if (rc < 0) { + RIL_LOGE("Sending to %s client failed", client->name); + goto error; } rc = 0; goto complete; error: - ril_radio_state_update(RADIO_STATE_UNAVAILABLE); - ril_sms_send(RIL_SMS_NUMBER, "Samsung-RIL: The modem just crashed, please reboot your device if you can't get service back."); + eventfd_send(ipc_fmt_data->event_fd, IPC_CLIENT_IO_ERROR); rc = -1; complete: + release_wake_lock(RIL_VERSION_STRING); + RIL_CLIENT_UNLOCK(client); + return rc; } -int ipc_fmt_create(struct ril_client *client) +unsigned char ipc_fmt_seq(void) { - struct ipc_client *ipc_client; + struct ril_client *client; + struct ipc_fmt_data *data; - int rc; + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return 0xff; + + data = (struct ipc_fmt_data *) client->data; + data->seq++; + + if (data->seq % 0xff == 0x00) + data->seq = 0x01; + + return data->seq; +} + +unsigned char ipc_fmt_request_seq(RIL_Token token) +{ + struct ril_client *client; + struct ipc_fmt_request *request; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); if (client == NULL) - return -EINVAL; + return 0xff; - RIL_LOGD("Creating new FMT client"); + request = ipc_fmt_request_find_token(client, token); + if (request == NULL) + return 0xff; - ipc_client = ipc_client_create(IPC_CLIENT_TYPE_FMT); - if (ipc_client == NULL) { - RIL_LOGE("FMT client creation failed"); - goto error_client_create; - } + if (request->seq == 0xff) + request->seq = ipc_fmt_seq(); - client->data = (void *) ipc_client; + return request->seq; +} - RIL_LOGD("Setting log handler"); +RIL_Token ipc_fmt_request_token(unsigned char seq) +{ + struct ril_client *client; + struct ipc_fmt_request *request; - rc = ipc_client_set_log_callback(ipc_client, ipc_log_handler, NULL); - if (rc < 0) { - RIL_LOGE("Setting log handler failed"); - goto error_log_callback; - } + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL) + return NULL; - RIL_LOGD("Creating data"); + request = ipc_fmt_request_find_seq(client, seq); + if (request == NULL) + return NULL; - rc = ipc_client_data_create(ipc_client); - if (rc < 0) { - RIL_LOGE("Creating data failed"); - goto error_data_create; - } + return request->token; +} - RIL_LOGD("Starting bootstrap"); +/* + * IPC FMT client + */ - rc = ipc_client_bootstrap(ipc_client); - if (rc < 0) { - RIL_LOGE("Modem bootstrap failed"); - goto error_bootstrap; +int ipc_fmt_create(struct ril_client *client) +{ + struct ipc_fmt_data *data = NULL; + struct ipc_client *ipc_client = NULL; + int event_fd = -1; + int rc = 0; + + if (client == NULL) + return -1; + + + RIL_CLIENT_LOCK(client); + + client->available = 0; + + data = (struct ipc_fmt_data *) calloc(1, sizeof(struct ipc_fmt_data)); + + event_fd = eventfd(0, EFD_NONBLOCK); + if (event_fd < 0) { + RIL_LOGE("Creating %s event failed", client->name); + goto error; } - RIL_LOGD("Client power on..."); + data->event_fd = event_fd; + + ipc_client = ipc_client_create(IPC_CLIENT_TYPE_FMT); + if (ipc_client == NULL) { + RIL_LOGE("Creating %s client failed", client->name); + goto error; + } - rc = ipc_client_power_on(ipc_client); + rc = ipc_client_data_create(ipc_client); if (rc < 0) { - RIL_LOGE("%s: failed to power on ipc client", __func__); - goto error_power_on; + RIL_LOGE("Creating %s client data failed", client->name); + goto error; } - RIL_LOGD("Client open..."); + rc = ipc_client_log_callback_register(ipc_client, ipc_log_handler, NULL); + if (rc < 0) { + RIL_LOGE("Setting %s client log handler failed", client->name); + goto error; + } - rc = ipc_client_open(ipc_client); + rc = ipc_client_boot(ipc_client); if (rc < 0) { - RIL_LOGE("%s: failed to open ipc client", __func__); - goto error_open; + RIL_LOGE("Booting %s client failed", client->name); + goto error; } - RIL_LOGD("IPC FMT client done"); + data->ipc_client = ipc_client; + client->data = (void *) data; - return 0; + rc = 0; + goto complete; error: - ipc_client_power_off(ipc_client); + if (event_fd >= 0) + close(event_fd); -error_power_on: -error_get_fd: - ipc_client_close(ipc_client); + if (ipc_client != NULL) { + ipc_client_data_destroy(ipc_client); + ipc_client_destroy(ipc_client); + } -error_open: -error_bootstrap: - ipc_client_data_destroy(ipc_client); + if (data != NULL) + free(data); -error_data_create: -error_log_callback: - ipc_client_destroy(ipc_client); + rc = -1; -error_client_create: - client->data = NULL; +complete: + RIL_CLIENT_UNLOCK(client); - return -1; + return rc; } int ipc_fmt_destroy(struct ril_client *client) { - struct ipc_client *ipc_client; + struct ipc_fmt_data *data; - int rc; + if (client == NULL || client->data == NULL) + return -1; - if (client == NULL || client->data == NULL) { - RIL_LOGE("Client was already destroyed"); - return 0; - } + data = (struct ipc_fmt_data *) client->data; - ipc_client = (struct ipc_client *) client->data; + if (client->available) + ipc_fmt_close(client); - RIL_LOGD("Destroying ipc fmt client"); + RIL_CLIENT_LOCK(client); - if (ipc_client != NULL) { - ipc_client_power_off(ipc_client); - ipc_client_close(ipc_client); - ipc_client_data_destroy(ipc_client); - ipc_client_destroy(ipc_client); + client->available = 0; + + if (data->event_fd >= 0) + close(data->event_fd); + + if (data->ipc_client != NULL) { + ipc_client_data_destroy(data->ipc_client); + ipc_client_destroy(data->ipc_client); } + RIL_CLIENT_UNLOCK(client); + + ipc_fmt_flush(client); + + RIL_CLIENT_LOCK(client); + + memset(data, 0, sizeof(struct ipc_fmt_data)); + free(data); + client->data = NULL; + RIL_CLIENT_UNLOCK(client); + return 0; } -/* - * IPC RFS - */ +int ipc_fmt_open(struct ril_client *client) +{ + struct ipc_fmt_data *data; + int rc; + + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_fmt_data *) client->data; + if (data->ipc_client == NULL || data->event_fd < 0) + return -1; + + RIL_CLIENT_LOCK(client); + + if (client->failures != 1) { + rc = ipc_client_power_on(data->ipc_client); + if (rc < 0) { + RIL_LOGE("Powering on %s client failed", client->name); + goto error; + } + } + + rc = ipc_client_open(data->ipc_client); + if (rc < 0) { + RIL_LOGE("Opening %s client failed", client->name); + goto error; + } + + eventfd_flush(data->event_fd); + + client->available = 1; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); -void ipc_rfs_send(const unsigned short command, unsigned char *data, const int length, unsigned char mseq) + return rc; +} + +int ipc_fmt_close(struct ril_client *client) { - struct ipc_client *ipc_client; + struct ipc_fmt_data *data; + int rc; - if (ril_data.ipc_rfs_client == NULL || ril_data.ipc_rfs_client->data == NULL) - return; + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_fmt_data *) client->data; + if (data->ipc_client == NULL || data->event_fd < 0) + return -1; - ipc_client = (struct ipc_client *) ril_data.ipc_rfs_client->data; + RIL_CLIENT_LOCK(client); - RIL_CLIENT_LOCK(ril_data.ipc_rfs_client); - ipc_client_send(ipc_client, command, 0, data, length, mseq); - RIL_CLIENT_UNLOCK(ril_data.ipc_rfs_client); + client->available = 0; + + rc = eventfd_send(data->event_fd, IPC_CLIENT_CLOSE); + if (rc < 0) { + RIL_LOGE("Sending %s close event failed", client->name); + goto error; + } + + rc = ipc_client_close(data->ipc_client); + if (rc < 0) { + RIL_LOGE("Closing %s client failed", client->name); + goto error; + } + + if (client->failures != 1) { + rc = ipc_client_power_off(data->ipc_client); + if (rc < 0) { + RIL_LOGE("Powering off %s client failed", client->name); + goto error; + } + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); + + return rc; } -int ipc_rfs_read_loop(struct ril_client *client) +int ipc_fmt_dispatch(struct ril_client *client, struct ipc_message *message) { - struct ipc_client *ipc_client; - struct ipc_message_info info; + unsigned int i; + int rc; + + if (client == NULL || message == NULL || ril_data == NULL) + return -1; + RIL_LOCK(); + + for (i = 0; i < ipc_fmt_dispatch_handlers_count; i++) { + if (ipc_fmt_dispatch_handlers[i].handler == NULL) + continue; + + if (ipc_fmt_dispatch_handlers[i].command == message->command) { + rc = ipc_fmt_dispatch_handlers[i].handler(message); + if (rc < 0) + goto error; + + rc = 0; + goto complete; + } + } + + RIL_LOGD("Unhandled %s message: %s", client->name, ipc_command_string(message->command)); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + RIL_UNLOCK(); + + return rc; +} + +int ipc_fmt_loop(struct ril_client *client) +{ + struct ipc_fmt_data *data; + struct ipc_message message; + struct ipc_poll_fds fds; + int fds_array[] = { 0 }; + unsigned int count; + eventfd_t event; int rc; if (client == NULL || client->data == NULL) - return -EINVAL; + return -1; + + data = (struct ipc_fmt_data *) client->data; + if (data->ipc_client == NULL || data->event_fd < 0) + return -1; + + memset(&fds, 0, sizeof(fds)); + fds.fds = (int *) &fds_array; - ipc_client = (struct ipc_client *) client->data; + count = sizeof(fds_array) / sizeof(int); while (1) { - rc = ipc_client_poll(ipc_client, NULL); + if (!client->available) { + RIL_LOGE("%s client is not available", client->name); + return -1; + } + + fds_array[0] = data->event_fd; + fds.count = count; + + rc = ipc_client_poll(data->ipc_client, &fds, NULL); if (rc < 0) { - RIL_LOGE("IPC RFS client poll failed, aborting"); - goto error; + RIL_LOGE("Polling %s client failed", client->name); + return -1; } - memset(&info, 0, sizeof(info)); + if (fds.fds[0] == data->event_fd && fds.count > 0) { + rc = eventfd_recv(data->event_fd, &event); + if (rc < 0) + return -1; + + switch (event) { + case IPC_CLIENT_CLOSE: + return 0; + case IPC_CLIENT_IO_ERROR: + return -1; + } + } + + if ((unsigned int) rc == fds.count) + continue; + + memset(&message, 0, sizeof(message)); + RIL_LOCK(); RIL_CLIENT_LOCK(client); - if (ipc_client_recv(ipc_client, &info) < 0) { + acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING); + + rc = ipc_client_recv(data->ipc_client, &message); + if (rc < 0) { + RIL_LOGE("Receiving from %s client failed", client->name); + + release_wake_lock(RIL_VERSION_STRING); RIL_CLIENT_UNLOCK(client); - RIL_LOGE("IPC RFS recv failed, aborting"); - goto error; + RIL_UNLOCK(); + + return -1; } + + release_wake_lock(RIL_VERSION_STRING); RIL_CLIENT_UNLOCK(client); + RIL_UNLOCK(); + + rc = ipc_fmt_dispatch(client, &message); + if (rc < 0) { + RIL_LOGE("Dispatching %s message failed", client->name); - ipc_rfs_dispatch(&info); + if (message.data != NULL && message.size > 0) + free(message.data); - ipc_client_response_free(ipc_client, &info); + return -1; + } + + if (client->failures) + client->failures = 0; + + if (message.data != NULL && message.size > 0) + free(message.data); + } + + return 0; +} + +int ipc_fmt_request_register(struct ril_client *client, int request, + RIL_Token token) +{ + struct ipc_fmt_data *data; + struct ipc_fmt_request *ipc_fmt_request; + struct list_head *list_end; + struct list_head *list; + + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_fmt_data *) client->data; + + RIL_CLIENT_LOCK(client); + + ipc_fmt_request = (struct ipc_fmt_request *) calloc(1, sizeof(struct ipc_fmt_request)); + ipc_fmt_request->request = request; + ipc_fmt_request->token = token; + ipc_fmt_request->seq = 0xff; + + list_end = data->requests; + while (list_end != NULL && list_end->next != NULL) + list_end = list_end->next; + + list = list_head_alloc(list_end, NULL, (void *) ipc_fmt_request); + + if (data->requests == NULL) + data->requests = list; + + RIL_CLIENT_UNLOCK(client); + + return 0; +} + +int ipc_fmt_request_unregister(struct ril_client *client, int request, + RIL_Token token) +{ + struct ipc_fmt_data *data; + struct ipc_fmt_request *ipc_fmt_request; + struct list_head *list; + + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_fmt_data *) client->data; + + RIL_CLIENT_LOCK(client); + + list = data->requests; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + ipc_fmt_request = (struct ipc_fmt_request *) list->data; + + if (ipc_fmt_request->request == request && ipc_fmt_request->token == token) { + memset(ipc_fmt_request, 0, sizeof(struct ipc_fmt_request)); + free(ipc_fmt_request); + + if (list == data->requests) + data->requests = list->next; + + list_head_free(list); + + break; + } + +list_continue: + list = list->next; + } + + RIL_CLIENT_UNLOCK(client); + + return 0; +} + +int ipc_fmt_request_flush(struct ril_client *client) +{ + struct ipc_fmt_data *data; + struct ipc_fmt_request *ipc_fmt_request; + struct list_head *list; + struct list_head *list_next; + + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_fmt_data *) client->data; + + RIL_CLIENT_LOCK(client); + + list = data->requests; + while (list != NULL) { + if (list->data != NULL) { + ipc_fmt_request = (struct ipc_fmt_request *) list->data; + + memset(ipc_fmt_request, 0, sizeof(struct ipc_fmt_request)); + free(ipc_fmt_request); + } + + if (list == data->requests) + data->requests = list->next; + + list_next = list->next; + + list_head_free(list); + +list_continue: + list = list_next; + } + + RIL_CLIENT_UNLOCK(client); + + return 0; +} + +struct ipc_fmt_request *ipc_fmt_request_find_token(struct ril_client *client, + RIL_Token token) +{ + struct ipc_fmt_data *data; + struct ipc_fmt_request *request; + struct list_head *list; + + if (client == NULL || client->data == NULL) + return NULL; + + data = (struct ipc_fmt_data *) client->data; + + RIL_CLIENT_LOCK(client); + + list = data->requests; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + request = (struct ipc_fmt_request *) list->data; + + if (request->token == token) { + RIL_CLIENT_UNLOCK(client); + return request; + } + +list_continue: + list = list->next; + } + + RIL_CLIENT_UNLOCK(client); + + return NULL; +} + +struct ipc_fmt_request *ipc_fmt_request_find_seq(struct ril_client *client, + unsigned char seq) +{ + struct ipc_fmt_data *data; + struct ipc_fmt_request *request; + struct list_head *list; + + if (client == NULL || client->data == NULL) + return NULL; + + data = (struct ipc_fmt_data *) client->data; + + RIL_CLIENT_LOCK(client); + + list = data->requests; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + request = (struct ipc_fmt_request *) list->data; + + if (request->seq == seq) { + RIL_CLIENT_UNLOCK(client); + return request; + } + +list_continue: + list = list->next; + } + + RIL_CLIENT_UNLOCK(client); + + return NULL; +} + +int ipc_fmt_flush(struct ril_client *client) +{ + struct ipc_fmt_data *data; + + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_fmt_data *) client->data; + + ipc_fmt_request_flush(client); + + ipc_gen_phone_res_expect_flush(client); + + RIL_CLIENT_LOCK(client); + + memset(&data->sim_icc_type_data, 0, sizeof(data->sim_icc_type_data)); + memset(&data->hsdpa_status_data, 0, sizeof(data->hsdpa_status_data)); + data->svc_session = 0; + + data->seq = 0x00; + + RIL_CLIENT_UNLOCK(client); + + return 0; +} +/* + * IPC RFS + */ + +int ipc_rfs_send(unsigned char mseq, unsigned short command, const void *data, + size_t size) +{ + struct ril_client *client; + struct ipc_rfs_data *ipc_rfs_data; + int rc; + + client = ril_client_find_id(RIL_CLIENT_IPC_RFS); + if (client == NULL || client->data == NULL) + return -1; + + ipc_rfs_data = (struct ipc_rfs_data *) client->data; + if (ipc_rfs_data->ipc_client == NULL || ipc_rfs_data->event_fd < 0) + return -1; + + if (!client->available) { + RIL_LOGE("%s client is not available", client->name); + return -1; + } + + RIL_CLIENT_LOCK(client); + acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING); + + rc = ipc_client_send(ipc_rfs_data->ipc_client, mseq, command, 0x00, data, size); + if (rc < 0) { + RIL_LOGE("Sending to %s client failed", client->name); + goto error; } rc = 0; goto complete; error: - ril_radio_state_update(RADIO_STATE_UNAVAILABLE); - ril_sms_send(RIL_SMS_NUMBER, "Samsung-RIL: The modem just crashed, please reboot your device if you can't get service back."); + eventfd_send(ipc_rfs_data->event_fd, IPC_CLIENT_IO_ERROR); rc = -1; complete: + release_wake_lock(RIL_VERSION_STRING); + RIL_CLIENT_UNLOCK(client); + return rc; } +/* + * IPC RFS client + */ + int ipc_rfs_create(struct ril_client *client) { - struct ipc_client *ipc_client; - - int rc; + struct ipc_rfs_data *data = NULL; + struct ipc_client *ipc_client = NULL; + int event_fd = -1; + int rc = 0; if (client == NULL) - return -EINVAL; - - RIL_LOGD("Creating new RFS client"); + return -1; - ipc_client = ipc_client_create(IPC_CLIENT_TYPE_RFS); - if (ipc_client == NULL) { - RIL_LOGE("RFS client creation failed"); - goto error_client_create; - } + data = (struct ipc_rfs_data *) calloc(1, sizeof(struct ipc_rfs_data)); - client->data = (void *) ipc_client; + RIL_CLIENT_LOCK(client); - RIL_LOGD("Setting log handler"); + client->available = 0; - rc = ipc_client_set_log_callback(ipc_client, ipc_log_handler, NULL); - if (rc < 0) { - RIL_LOGE("Setting log handler failed"); - goto error_log_callback; + event_fd = eventfd(0, EFD_NONBLOCK); + if (event_fd < 0) { + RIL_LOGE("Creating %s event failed", client->name); + goto error; } - RIL_LOGD("Creating data"); + data->event_fd = event_fd; + + ipc_client = ipc_client_create(IPC_CLIENT_TYPE_RFS); + if (ipc_client == NULL) { + RIL_LOGE("Creating %s client failed", client->name); + goto error; + } rc = ipc_client_data_create(ipc_client); if (rc < 0) { - RIL_LOGE("Creating data failed"); - goto error_data_create; + RIL_LOGE("Creating %s client data failed", client->name); + goto error; } - RIL_LOGD("Client open..."); - - rc = ipc_client_open(ipc_client); + rc = ipc_client_log_callback_register(ipc_client, ipc_log_handler, NULL); if (rc < 0) { - RIL_LOGE("%s: failed to open ipc client", __func__); - goto error_open; + RIL_LOGE("Setting %s client log handler failed", client->name); + goto error; } - RIL_LOGD("IPC RFS client done"); + data->ipc_client = ipc_client; + client->data = (void *) data; - return 0; + rc = 0; + goto complete; error: -error_get_fd: - ipc_client_close(ipc_client); + if (event_fd >= 0) + close(event_fd); -error_open: - ipc_client_data_destroy(ipc_client); + if (ipc_client != NULL) { + ipc_client_data_destroy(ipc_client); + ipc_client_destroy(ipc_client); + } -error_data_create: -error_log_callback: - ipc_client_destroy(ipc_client); + if (data != NULL) + free(data); -error_client_create: - client->data = NULL; + rc = -1; - return -1; -} +complete: + RIL_CLIENT_UNLOCK(client); + return rc; +} int ipc_rfs_destroy(struct ril_client *client) { - struct ipc_client *ipc_client; + struct ipc_rfs_data *data; + + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_rfs_data *) client->data; + + if (client->available) + ipc_rfs_close(client); + + RIL_CLIENT_LOCK(client); + + client->available = 0; + + if (data->event_fd >= 0) + close(data->event_fd); + + if (data->ipc_client != NULL) { + ipc_client_data_destroy(data->ipc_client); + ipc_client_destroy(data->ipc_client); + } + + memset(data, 0, sizeof(struct ipc_rfs_data)); + free(data); + + client->data = NULL; + + RIL_CLIENT_UNLOCK(client); + + return 0; +} +int ipc_rfs_open(struct ril_client *client) +{ + struct ipc_rfs_data *data; int rc; - if (client == NULL || client->data == NULL) { - RIL_LOGE("Client was already destroyed"); - return 0; + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_rfs_data *) client->data; + if (data->ipc_client == NULL || data->event_fd < 0) + return -1; + + RIL_CLIENT_LOCK(client); + + rc = ipc_client_open(data->ipc_client); + if (rc < 0) { + RIL_LOGE("Opening %s client failed", client->name); + goto error; } - ipc_client = (struct ipc_client *) client->data; + eventfd_flush(data->event_fd); - RIL_LOGD("Destroying ipc rfs client"); + client->available = 1; - if (ipc_client != NULL) { - ipc_client_close(ipc_client); - ipc_client_data_destroy(ipc_client); - ipc_client_destroy(ipc_client); + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); + + return rc; +} + +int ipc_rfs_close(struct ril_client *client) +{ + struct ipc_rfs_data *data; + int rc; + + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_rfs_data *) client->data; + if (data->ipc_client == NULL || data->event_fd < 0) + return -1; + + RIL_CLIENT_LOCK(client); + + client->available = 0; + + rc = eventfd_send(data->event_fd, IPC_CLIENT_CLOSE); + if (rc < 0) { + RIL_LOGE("Sending %s close event failed", client->name); + goto error; } - client->data = NULL; + rc = ipc_client_close(data->ipc_client); + if (rc < 0) { + RIL_LOGE("Closing %s client failed", client->name); + goto error; + } + + rc = ipc_client_power_off(data->ipc_client); + if (rc < 0) { + RIL_LOGE("Powering off %s client failed", client->name); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); + + return rc; +} + +int ipc_rfs_dispatch(struct ril_client *client, struct ipc_message *message) +{ + unsigned int i; + int rc; + + if (client == NULL || message == NULL || ril_data == NULL) + return -1; + + RIL_LOCK(); + + for (i = 0; i < ipc_rfs_dispatch_handlers_count; i++) { + if (ipc_rfs_dispatch_handlers[i].handler == NULL) + continue; + + if (ipc_rfs_dispatch_handlers[i].command == message->command) { + rc = ipc_rfs_dispatch_handlers[i].handler(message); + if (rc < 0) + goto error; + + rc = 0; + goto complete; + } + } + + RIL_LOGD("Unhandled %s message: %s", client->name, ipc_command_string(message->command)); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + RIL_UNLOCK(); + + return rc; +} + +int ipc_rfs_loop(struct ril_client *client) +{ + struct ipc_rfs_data *data; + struct ipc_message message; + struct ipc_poll_fds fds; + int fds_array[] = { 0 }; + unsigned int count; + eventfd_t event; + int rc; + + if (client == NULL || client->data == NULL) + return -1; + + data = (struct ipc_rfs_data *) client->data; + if (data->ipc_client == NULL || data->event_fd < 0) + return -1; + + memset(&fds, 0, sizeof(fds)); + fds.fds = (int *) &fds_array; + + count = sizeof(fds_array) / sizeof(int); + + while (1) { + if (!client->available) { + RIL_LOGE("%s client is not available", client->name); + return -1; + } + + fds_array[0] = data->event_fd; + fds.count = count; + + rc = ipc_client_poll(data->ipc_client, &fds, NULL); + if (rc < 0) { + RIL_LOGE("Polling %s client failed", client->name); + return -1; + } + + if (fds.fds[0] == data->event_fd && fds.count > 0) { + rc = eventfd_recv(data->event_fd, &event); + if (rc < 0) + return -1; + + switch (event) { + case IPC_CLIENT_CLOSE: + return 0; + case IPC_CLIENT_IO_ERROR: + return -1; + } + } + + if ((unsigned int) rc == fds.count) + continue; + + memset(&message, 0, sizeof(message)); + + RIL_LOCK(); + RIL_CLIENT_LOCK(client); + acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING); + + rc = ipc_client_recv(data->ipc_client, &message); + if (rc < 0) { + RIL_LOGE("Receiving from %s client failed", client->name); + + release_wake_lock(RIL_VERSION_STRING); + RIL_CLIENT_UNLOCK(client); + RIL_UNLOCK(); + + return -1; + } + + release_wake_lock(RIL_VERSION_STRING); + RIL_CLIENT_UNLOCK(client); + RIL_UNLOCK(); + + rc = ipc_rfs_dispatch(client, &message); + if (rc < 0) { + RIL_LOGE("Dispatching %s message failed", client->name); + + if (message.data != NULL && message.size > 0) + free(message.data); + + return -1; + } + + if (client->failures) + client->failures = 0; + + if (message.data != NULL && message.size > 0) + free(message.data); + } return 0; } /* - * IPC clients structures + * RIL clients */ -struct ril_client_funcs ipc_fmt_client_funcs = { +struct ril_client_handlers ipc_fmt_handlers = { .create = ipc_fmt_create, .destroy = ipc_fmt_destroy, - .read_loop = ipc_fmt_read_loop, + .open = ipc_fmt_open, + .close = ipc_fmt_close, + .loop = ipc_fmt_loop, }; -struct ril_client_funcs ipc_rfs_client_funcs = { +struct ril_client_handlers ipc_rfs_handlers = { .create = ipc_rfs_create, .destroy = ipc_rfs_destroy, - .read_loop = ipc_rfs_read_loop, + .open = ipc_rfs_open, + .close = ipc_rfs_close, + .loop = ipc_rfs_loop, +}; + +struct ril_client_callbacks ipc_fmt_callbacks = { + .request_register = ipc_fmt_request_register, + .request_unregister = ipc_fmt_request_unregister, + .flush = ipc_fmt_flush, +}; + +struct ril_client_callbacks ipc_rfs_callbacks = { + .request_register = NULL, + .request_unregister = NULL, + .flush = NULL, +}; + +struct ril_client ipc_fmt_client = { + .id = RIL_CLIENT_IPC_FMT, + .name = "IPC FMT", + .critical = 1, + .handlers = &ipc_fmt_handlers, + .callbacks = &ipc_fmt_callbacks, +}; + +struct ril_client ipc_rfs_client = { + .id = RIL_CLIENT_IPC_RFS, + .name = "IPC RFS", + .critical = 0, + .handlers = &ipc_rfs_handlers, + .callbacks = &ipc_rfs_callbacks, }; @@ -1,8 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,21 +20,106 @@ #ifndef _SAMSUNG_RIL_IPC_H_ #define _SAMSUNG_RIL_IPC_H_ -#include "samsung-ril.h" +#include <stdlib.h> -#define ipc_fmt_send_get(command, mseq) \ - ipc_fmt_send(command, IPC_TYPE_GET, NULL, 0, mseq) +#include <samsung-ril.h> -#define ipc_fmt_send_set(command, mseq, data, length) \ - ipc_fmt_send(command, IPC_TYPE_SET, data, length, mseq) +struct ril_client; -#define ipc_fmt_send_exec(command, mseq) \ - ipc_fmt_send(command, IPC_TYPE_EXEC, NULL, 0, mseq) +/* + * Values + */ + +#define IPC_CLIENT_CLOSE 0x00 +#define IPC_CLIENT_IO_ERROR 0x01 + +/* + * Structures + */ + +struct ipc_fmt_request { + int request; + RIL_Token token; + unsigned char seq; +}; + +struct ipc_fmt_data { + struct ipc_client *ipc_client; + int event_fd; + + struct list_head *gen_phone_res_expect; + + struct ipc_sec_sim_icc_type_data sim_icc_type_data; + struct ipc_gprs_hsdpa_status_data hsdpa_status_data; + int svc_session; + + struct list_head *requests; + unsigned char seq; +}; + +struct ipc_rfs_data { + struct ipc_client *ipc_client; + int event_fd; +}; -extern struct ril_client_funcs ipc_fmt_client_funcs; -extern struct ril_client_funcs ipc_rfs_client_funcs; +struct ipc_dispatch_handler { + unsigned short command; + int (*handler)(struct ipc_message *message); +}; + +/* + * Helpers + */ + +/* Utils */ +void ipc_log_handler(void *log_data, const char *message); + +/* IPC FMT */ +int ipc_fmt_send(unsigned char mseq, unsigned short command, unsigned char type, + const void *data, size_t size); +unsigned char ipc_fmt_seq(void); +unsigned char ipc_fmt_request_seq(RIL_Token token); +RIL_Token ipc_fmt_request_token(unsigned char seq); + +/* IPC FMT client */ +int ipc_fmt_create(struct ril_client *client); +int ipc_fmt_destroy(struct ril_client *client); +int ipc_fmt_open(struct ril_client *client); +int ipc_fmt_close(struct ril_client *client); +int ipc_fmt_dispatch(struct ril_client *client, struct ipc_message *message); +int ipc_fmt_loop(struct ril_client *client); +int ipc_fmt_request_register(struct ril_client *client, int request, + RIL_Token token); +int ipc_fmt_request_unregister(struct ril_client *client, int request, + RIL_Token token); +int ipc_fmt_request_flush(struct ril_client *client); +struct ipc_fmt_request *ipc_fmt_request_find_token(struct ril_client *client, + RIL_Token token); +struct ipc_fmt_request *ipc_fmt_request_find_seq(struct ril_client *client, + unsigned char seq); +int ipc_fmt_flush(struct ril_client *client); + +/* IPC RFS */ +int ipc_rfs_send(unsigned char mseq, unsigned short command, const void *data, + size_t size); + +/* IPC RFS client */ +int ipc_rfs_create(struct ril_client *client); +int ipc_rfs_destroy(struct ril_client *client); +int ipc_rfs_open(struct ril_client *client); +int ipc_rfs_close(struct ril_client *client); +int ipc_rfs_dispatch(struct ril_client *client, struct ipc_message *message); +int ipc_rfs_loop(struct ril_client *client); + +/* + * RIL clients + */ -void ipc_fmt_send(const unsigned short command, const char type, unsigned char *data, const int length, unsigned char mseq); -void ipc_rfs_send(const unsigned short command, unsigned char *data, const int length, unsigned char mseq); +extern struct ril_client_handlers ipc_fmt_handlers; +extern struct ril_client_handlers ipc_rfs_handlers; +extern struct ril_client_callbacks ipc_fmt_callbacks; +extern struct ril_client_callbacks ipc_rfs_callbacks; +extern struct ril_client ipc_fmt_client; +extern struct ril_client ipc_rfs_client; #endif @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,256 +18,270 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ -#define LOG_TAG "RIL-MISC" +#include <stdlib.h> + +#define LOG_TAG "RIL" #include <utils/Log.h> -#include "samsung-ril.h" -#include "util.h" +#include <samsung-ril.h> -void ril_request_get_imei_send(RIL_Token t) +int ipc_misc_me_version(struct ipc_message *message) { - unsigned char data; + struct ipc_misc_me_version_response_data *data; + char *baseband_version; + int active; - data = IPC_MISC_ME_SN_SERIAL_NUM; - ipc_fmt_send(IPC_MISC_ME_SN, IPC_TYPE_GET, (unsigned char *) &data, sizeof(data), ril_request_get_id(t)); -} + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_misc_me_version_response_data)) + return -1; -void ril_request_get_imei(RIL_Token t) -{ - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; - if (ril_data.tokens.get_imei) { - RIL_LOGD("Another IMEI request is waiting, aborting"); - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } + data = (struct ipc_misc_me_version_response_data *) message->data; - ril_data.tokens.get_imei = t; + baseband_version = strndup(data->software_version, sizeof(data->software_version)); - if (ril_data.tokens.get_imeisv) { - RIL_LOGD("IMEISV token found: %p", ril_data.tokens.get_imeisv); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) baseband_version, sizeof(baseband_version)); - ril_request_get_imei_send(ril_data.tokens.get_imei); - } else { - RIL_LOGD("Waiting for IMEISV token"); - } + free(baseband_version); + + return 0; } -void ril_request_get_imeisv(RIL_Token t) +int ril_request_baseband_version(void *data, size_t size, RIL_Token token) { - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; + struct ipc_misc_me_version_request_data request_data; + struct ril_request *request; + int rc; - if (ril_data.tokens.get_imeisv) { - RIL_LOGD("Another IMEISV request is waiting, aborting"); - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - ril_data.tokens.get_imeisv = t; - - if (ril_data.tokens.get_imei) { - RIL_LOGD("IMEI token found: %p", ril_data.tokens.get_imei); - - ril_request_get_imei_send(ril_data.tokens.get_imei); - } else { - RIL_LOGD("Waiting for IMEI token"); - } -} - -void ipc_misc_me_sn_imei(struct ipc_message_info *info) -{ - struct ipc_misc_me_sn *imei_info; - RIL_Token t; - char imei[33]; - char imeisv[3]; + request = ril_request_find_request_status(RIL_REQUEST_BASEBAND_VERSION, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - if (info->type != IPC_TYPE_RESP) + rc = ipc_misc_me_version_setup(&request_data); + if (rc < 0) goto error; - if (info->data == NULL || info->length < sizeof(struct ipc_misc_me_sn)) + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_MISC_ME_VERSION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) goto error; - imei_info = (struct ipc_misc_me_sn *) info->data; - t = ril_request_get_token(info->aseq); + rc = RIL_REQUEST_HANDLED; + goto complete; - if (ril_data.tokens.get_imei != t) - RIL_LOGE("IMEI tokens mismatch (%p and %p)", - ril_data.tokens.get_imei, t); +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); - if (imei_info->length > 32) - return; + rc = RIL_REQUEST_COMPLETED; - memset(imei, 0, sizeof(imei)); - memset(imeisv, 0, sizeof(imeisv)); +complete: + return rc; +} - memcpy(imei, imei_info->data, imei_info->length); +int ipc_misc_me_imsi(struct ipc_message *message) +{ + char *imsi; - // Last two bytes of IMEI in imei_info are the SV bytes - memcpy(imeisv, (imei_info->data + imei_info->length - 2), 2); + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_misc_me_imsi_header)) + return -1; - // In case of token mismatch, complete both requests - if (t && ril_data.tokens.get_imei != t) { - ril_request_complete(t, RIL_E_SUCCESS, imei, sizeof(char *)); - } + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; - // IMEI - if (ril_data.tokens.get_imei) { - ril_request_complete(ril_data.tokens.get_imei, - RIL_E_SUCCESS, imei, sizeof(char *)); - ril_data.tokens.get_imei = 0; + imsi = ipc_misc_me_imsi_imsi_extract(message->data, message->size); + if (imsi == NULL) { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return 0; } - // IMEI SV - if (ril_data.tokens.get_imeisv) { - ril_request_complete(ril_data.tokens.get_imeisv, - RIL_E_SUCCESS, imeisv, sizeof(char *)); - ril_data.tokens.get_imeisv = 0; - } + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) imsi, sizeof(imsi)); - return; + free(imsi); -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return 0; } -void ipc_misc_me_sn(struct ipc_message_info *info) +int ril_request_get_imsi(void *data, size_t size, RIL_Token token) { - struct ipc_misc_me_sn *me_sn_info; - - if (info->type != IPC_TYPE_RESP) - return; + struct ril_request *request; + int rc; - if (info->data == NULL || info->length < sizeof(struct ipc_misc_me_sn)) - goto error; + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - me_sn_info = (struct ipc_misc_me_sn *) info->data; + request = ril_request_find_request_status(RIL_REQUEST_GET_IMSI, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - switch (me_sn_info->type) { - case IPC_MISC_ME_SN_SERIAL_NUM: - ipc_misc_me_sn_imei(info); - break; - case IPC_MISC_ME_SN_SERIAL_NUM_SERIAL: - RIL_LOGD("Got IPC_MISC_ME_SN_SERIAL_NUM_SERIAL: %s\n", - me_sn_info->data); - break; + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_MISC_ME_IMSI, IPC_TYPE_GET, NULL, 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; } - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_HANDLED; } -void ril_request_baseband_version(RIL_Token t) +int ipc_misc_me_sn(struct ipc_message *message) { - unsigned char data; + struct ipc_misc_me_sn_response_data *data; + struct ril_request *request; + char *imei; + char *imeisv; + unsigned int offset; - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_misc_me_sn_response_data)) + return -1; - if (ril_data.tokens.baseband_version) { - RIL_LOGD("Another Baseband version request is waiting, aborting"); - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } + if (message->type != IPC_TYPE_RESP) + return 0; - ril_data.tokens.baseband_version = t; + data = (struct ipc_misc_me_sn_response_data *) message->data; - data = 0xff; + if (data->type != IPC_MISC_ME_SN_SERIAL_NUM) + return 0; - ipc_fmt_send(IPC_MISC_ME_VERSION, IPC_TYPE_GET, (unsigned char *) &data, sizeof(data), ril_request_get_id(t)); -} - -void ipc_misc_me_version(struct ipc_message_info *info) -{ - char sw_version[33]; - struct ipc_misc_me_version *version; - RIL_Token t; + imei = ipc_misc_me_sn_extract(data); + if (imei == NULL) { + 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); - if (info->type != IPC_TYPE_RESP) - return; + 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); - if (info->data == NULL || info->length < sizeof(struct ipc_misc_me_version)) - goto error; + return 0; + } - version = (struct ipc_misc_me_version *) info->data; - t = ril_request_get_token(info->aseq); + offset = strlen(imei) - 2; + imeisv = strdup((char *) (imei + offset)); - if (ril_data.tokens.baseband_version != t) - RIL_LOGE("Baseband tokens mismatch (%p and %p)", - ril_data.tokens.baseband_version, t); + imei[offset] = '\0'; - memcpy(sw_version, version->sw_version, 32); - sw_version[32] = '\0'; + 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)); - ril_request_complete(t, RIL_E_SUCCESS, sw_version, sizeof(sw_version)); - ril_data.tokens.baseband_version = 0; + 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)); - return; + free(imei); + free(imeisv); -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return 0; } -void ril_request_get_imsi(RIL_Token t) +int ril_request_get_imei(void *data, size_t size, RIL_Token token) { - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; + struct ipc_misc_me_sn_request_data request_data; + struct ril_request *request; + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - ipc_fmt_send_get(IPC_MISC_ME_IMSI, ril_request_get_id(t)); + 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; + + request_data.type = IPC_MISC_ME_SN_SERIAL_NUM; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_MISC_ME_SN, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + return RIL_REQUEST_HANDLED; } -void ipc_misc_me_imsi(struct ipc_message_info *info) +int ril_request_get_imeisv(void *data, size_t size, RIL_Token token) { - unsigned char imsi_length; - char *imsi; + struct ipc_misc_me_sn_request_data request_data; + struct ril_request *request; + int rc; - if (info->type != IPC_TYPE_RESP) - return; + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - if (info->data == NULL || info->length < sizeof(unsigned char)) - goto error; + 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; - imsi_length = *((unsigned char *) info->data); + request_data.type = IPC_MISC_ME_SN_SERIAL_NUM; - if (((int) info->length) < imsi_length + 1) { - RIL_LOGE("%s: missing IMSI data", __func__); - ril_request_complete(ril_request_get_token(info->aseq), - RIL_E_GENERIC_FAILURE, NULL, 0); - return; + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_MISC_ME_SN, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; } - imsi = (char *) calloc(1, imsi_length + 1); - memcpy(imsi, ((unsigned char *) info->data) + sizeof(unsigned char), imsi_length); - imsi[imsi_length] = '\0'; + return RIL_REQUEST_HANDLED; +} - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, imsi, imsi_length + 1); +int ipc_misc_time_info(struct ipc_message *message) +{ + struct ipc_misc_time_info_data *data; + char *string = NULL; - free(imsi); + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_misc_time_info_data)) + return -1; - return; + data = (struct ipc_misc_time_info_data *) message->data; -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + asprintf(&string, "%02u/%02u/%02u,%02u:%02u:%02u%c%02d,%02d", data->year, data->mon, data->day, data->hour, data->min, data->sec, data->tz < 0 ? '-' : '+', data->tz < 0 ? -data->tz : data->tz, data->dl); + + ril_request_unsolicited(RIL_UNSOL_NITZ_TIME_RECEIVED, string, sizeof(string)); + + if (string != NULL) + free(string); + + return 0; } -void ipc_misc_time_info(struct ipc_message_info *info) +int ril_request_screen_state(void *data, size_t size, RIL_Token token) { - struct ipc_misc_time_info *nitz; - char str[128]; + 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; - if (info->data == NULL || info->length < sizeof(struct ipc_misc_time_info)) - return; + value = *((int *) data); - nitz = (struct ipc_misc_time_info *) info->data; + if (value) +#if RIL_VERSION >= 6 + ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); +#else + ril_request_unsolicited(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); +#endif - sprintf(str, "%02u/%02u/%02u,%02u:%02u:%02u%c%02d,%02d", - nitz->year, nitz->mon, nitz->day, nitz->hour, - nitz->min, nitz->sec, nitz->tz < 0 ? '-' : '+', - nitz->tz < 0 ? -nitz->tz : nitz->tz, nitz->dl); + ril_request_complete(token, RIL_E_SUCCESS, NULL, 0); - ril_request_unsolicited(RIL_UNSOL_NITZ_TIME_RECEIVED, - str, strlen(str) + 1); + return RIL_REQUEST_COMPLETED; } @@ -1,916 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#define LOG_TAG "RIL-NET" -#include <utils/Log.h> - -#include "samsung-ril.h" -#include "util.h" - -#include <plmn_list.h> - -unsigned char ipc2ril_reg_state(unsigned char reg_state) -{ - switch (reg_state) { - case IPC_NET_REGISTRATION_STATE_NONE: - return 0; - case IPC_NET_REGISTRATION_STATE_HOME: - return 1; - case IPC_NET_REGISTRATION_STATE_SEARCHING: - return 2; - case IPC_NET_REGISTRATION_STATE_EMERGENCY: - return 10; - case IPC_NET_REGISTRATION_STATE_ROAMING: - return 5; - case IPC_NET_REGISTRATION_STATE_UNKNOWN: - return 4; - default: - RIL_LOGE("%s: invalid reg_state: %d", __func__, reg_state); - return 0; - } -} - -unsigned char ipc2ril_act(unsigned char act) -{ - switch (act) { - case IPC_NET_ACCESS_TECHNOLOGY_GPRS: - return 1; - case IPC_NET_ACCESS_TECHNOLOGY_EDGE: - return 2; - case IPC_NET_ACCESS_TECHNOLOGY_UMTS: - return 3; - case IPC_NET_ACCESS_TECHNOLOGY_GSM: - case IPC_NET_ACCESS_TECHNOLOGY_GSM2: - default: - return 0; - } -} - -unsigned char ipc2ril_gprs_act(unsigned char act) -{ - switch (act) { - case IPC_NET_ACCESS_TECHNOLOGY_GPRS: - return 1; - case IPC_NET_ACCESS_TECHNOLOGY_EDGE: - return 2; - case IPC_NET_ACCESS_TECHNOLOGY_UMTS: - return 3; - case IPC_NET_ACCESS_TECHNOLOGY_GSM: - case IPC_NET_ACCESS_TECHNOLOGY_GSM2: - default: - return 0; - } -} - -int ipc2ril_mode_sel(unsigned char mode) -{ - switch (mode) { - case 0: - return 7; // auto mode - case IPC_NET_MODE_SEL_GSM_UMTS: - return 0; - case IPC_NET_MODE_SEL_GSM_ONLY: - return 1; - case IPC_NET_MODE_SEL_UMTS_ONLY: - return 2; - default: - return 0; - } -} - -unsigned char ril2ipc_mode_sel(int mode) -{ - switch (mode) { - case 1: // GSM only - return IPC_NET_MODE_SEL_GSM_ONLY; - case 2: // WCDMA only - return IPC_NET_MODE_SEL_UMTS_ONLY; - case 0: - default: // GSM/WCDMA + the rest - return IPC_NET_MODE_SEL_GSM_UMTS; - } -} - -int ipc2ril_plmn_sel(unsigned char mode) -{ - switch (mode) { - case IPC_NET_PLMN_SEL_MANUAL: - return 1; - case IPC_NET_PLMN_SEL_AUTO: - return 0; - default: - return 0; - } -} - -unsigned char ril2ipc_plmn_sel(int mode) -{ - switch (mode) { - case 0: - return IPC_NET_PLMN_SEL_AUTO; - case 1: - return IPC_NET_PLMN_SEL_MANUAL; - default: - return 0; - } -} - -void ipc2ril_reg_state_resp(struct ipc_net_regist_response *netinfo, char *response[15]) -{ - unsigned char reg_state; - unsigned char act; - - if (netinfo == NULL || response == NULL) - return; - - reg_state = ipc2ril_reg_state(netinfo->reg_state); - act = ipc2ril_act(netinfo->act); - - memset(response, 0, sizeof(response)); - - asprintf(&response[0], "%d", reg_state); - asprintf(&response[1], "%x", netinfo->lac); - asprintf(&response[2], "%x", netinfo->cid); - asprintf(&response[3], "%d", act); -} - -void ipc2ril_gprs_reg_state_resp(struct ipc_net_regist_response *netinfo, char *response[4]) -{ - unsigned char reg_state; - unsigned char act; - - if (netinfo == NULL || response == NULL) - return; - - reg_state = ipc2ril_reg_state(netinfo->reg_state); - act = ipc2ril_gprs_act(netinfo->act); - - memset(response, 0, sizeof(response)); - - asprintf(&response[0], "%d", reg_state); - asprintf(&response[1], "%x", netinfo->lac); - asprintf(&response[2], "%x", netinfo->cid); - asprintf(&response[3], "%d", act); -} - -/* - * Set all the tokens to data waiting. - * For instance when only operator is updated by modem NOTI, we don't need - * to ask the modem new NET Regist and GPRS Net Regist states so act like we got - * these from modem NOTI too so we don't have to make the requests - */ -void ril_tokens_net_set_data_waiting(void) -{ - ril_data.tokens.registration_state = RIL_TOKEN_DATA_WAITING; - ril_data.tokens.gprs_registration_state = RIL_TOKEN_DATA_WAITING; - ril_data.tokens.operator = RIL_TOKEN_DATA_WAITING; -} - -/* - * Returns 1 if unsol data is waiting, 0 if not - */ -int ril_tokens_net_get_data_waiting(void) -{ - return ril_data.tokens.registration_state == RIL_TOKEN_DATA_WAITING || ril_data.tokens.gprs_registration_state == RIL_TOKEN_DATA_WAITING || ril_data.tokens.operator == RIL_TOKEN_DATA_WAITING; -} - -void ril_tokens_net_state_dump(void) -{ - RIL_LOGD("ril_tokens_net_state_dump:\n\ - \tril_data.tokens.registration_state = %p\n\ - \tril_data.tokens.gprs_registration_state = %p\n\ - \tril_data.tokens.operator = %p\n", ril_data.tokens.registration_state, ril_data.tokens.gprs_registration_state, ril_data.tokens.operator); -} - -void ril_plmn_split(char *plmn_data, char **plmn, unsigned int *mcc, unsigned int *mnc) -{ - char plmn_t[7]; - int i; - - memset(plmn_t, 0, sizeof(plmn_t)); - memcpy(plmn_t, plmn_data, 6); - - if (plmn_t[5] == '#') - plmn_t[5] = '\0'; - - if (plmn != NULL) { - *plmn = malloc(sizeof(plmn_t)); - memcpy(*plmn, plmn_t, sizeof(plmn_t)); - } - - if (mcc == NULL || mnc == NULL) - return; - - sscanf(plmn_t, "%3u%2u", mcc, mnc); -} - -void ril_plmn_string(char *plmn_data, char *response[3]) -{ - unsigned int mcc, mnc; - char *plmn = NULL; - - int plmn_entries; - int i; - - if (plmn_data == NULL || response == NULL) - return; - - ril_plmn_split(plmn_data, &plmn, &mcc, &mnc); - - asprintf(&response[2], "%s", plmn); - - if (plmn != NULL) - free(plmn); - - plmn_entries = sizeof(plmn_list) / sizeof(struct plmn_list_entry); - - RIL_LOGD("Found %d plmn records", plmn_entries); - - for (i = 0 ; i < plmn_entries ; i++) { - if (plmn_list[i].mcc == mcc && plmn_list[i].mnc == mnc) { - asprintf(&response[0], "%s", plmn_list[i].operator_long); - asprintf(&response[1], "%s", plmn_list[i].operator_short); - return; - } - } - - response[0] = NULL; - response[1] = NULL; -} - -/* - * How to handle NET unsol data from modem: - * 1- Rx UNSOL (NOTI) data from modem - * 2- copy data in a sized variable stored in radio - * 3- make sure no SOL request is going on for this token - * 4- copy data to radio structure - * 5- if no UNSOL data is already waiting for a token, tell RILJ NETWORK_STATE_CHANGED - * 6- set all the net tokens to RIL_TOKEN_DATA_WAITING - * 7- RILJ will ask for OPERATOR, GPRS_REG_STATE and REG_STATE - * for each request: - * 8- if token is RIL_TOKEN_DATA_WAITING it's SOL request for modem UNSOL data - * 9- send back modem data and tell E_SUCCESS to RILJ request - * 10- set token to 0x00 - * - * How to handle NET sol requests from RILJ: - * 1- if token is 0x00 it's UNSOL RILJ request for modem data - * 2- put RIL_Token in token - * 3- request data to the modem - * 4- Rx SOL (RESP) data from modem - * 5- copy data to radio structure - * 6- send back data to RILJ with token from modem message - * 7- if token != RIL_TOKEN_DATA_WAITING, reset token to 0x00 - * - * What if both are appening at the same time? - * 1- RILJ requests modem data (UNSOL) - * 2- token is 0x00 so send request to modem - * 3- UNSOL data arrives from modem - * 4- set all tokens to RIL_TOKEN_DATA_WAITING - * 5- store data, tell RILJ NETWORK_STATE_CHANGED - * 6- Rx requested data from modem - * 7- copy data to radio structure - * 8- token mismatch (is now RIL_TOKEN_DATA_WAITING) - * 9- send back data to RIL with token from IPC message - * 10- don't reset token to 0x00 - * 11- RILJ does SOL request for modem data (we know it's SOL because we didn't reset token) - * 12- send back last data we have (from UNSOL RILJ request here) - */ - -void ril_request_operator(RIL_Token t) -{ - char *response[3]; - size_t i; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - // IPC_NET_REGISTRATION_STATE_ROAMING is the biggest valid value - if (ril_data.state.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_NONE || - ril_data.state.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_SEARCHING || - ril_data.state.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_UNKNOWN || - ril_data.state.netinfo.reg_state > IPC_NET_REGISTRATION_STATE_ROAMING) { - ril_request_complete(t, RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW, NULL, 0); - - ril_data.tokens.operator = RIL_TOKEN_NULL; - return; - } - - if (ril_data.tokens.operator == RIL_TOKEN_DATA_WAITING) { - RIL_LOGD("Got RILJ request for UNSOL data"); - - /* Send back the data we got UNSOL */ - ril_plmn_string(ril_data.state.plmndata.plmn, response); - - ril_request_complete(t, RIL_E_SUCCESS, response, sizeof(response)); - - for (i = 0; i < sizeof(response) / sizeof(char *) ; i++) { - if (response[i] != NULL) - free(response[i]); - } - - ril_data.tokens.operator = RIL_TOKEN_NULL; - } else if (ril_data.tokens.operator == RIL_TOKEN_NULL) { - RIL_LOGD("Got RILJ request for SOL data"); - /* Request data to the modem */ - ril_data.tokens.operator = t; - - ipc_fmt_send_get(IPC_NET_CURRENT_PLMN, ril_request_get_id(t)); - } else { - RIL_LOGE("Another request is going on, returning UNSOL data"); - - /* Send back the data we got UNSOL */ - ril_plmn_string(ril_data.state.plmndata.plmn, response); - - ril_request_complete(t, RIL_E_SUCCESS, response, sizeof(response)); - - for (i = 0; i < sizeof(response) / sizeof(char *) ; i++) { - if (response[i] != NULL) - free(response[i]); - } - } - - ril_tokens_net_state_dump(); -} - -void ipc_net_current_plmn(struct ipc_message_info *info) -{ - struct ipc_net_current_plmn_response *plmndata; - RIL_Token t; - - char *response[3]; - size_t i; - - if (info->data == NULL || info->length < sizeof(struct ipc_net_current_plmn_response)) - goto error; - - plmndata = (struct ipc_net_current_plmn_response *) info->data; - t = ril_request_get_token(info->aseq); - - switch (info->type) { - case IPC_TYPE_NOTI: - RIL_LOGD("Got UNSOL Operator message"); - - // IPC_NET_REGISTRATION_STATE_ROAMING is the biggest valid value - if (ril_data.state.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_NONE || - ril_data.state.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_SEARCHING || - ril_data.state.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_UNKNOWN || - ril_data.state.netinfo.reg_state > IPC_NET_REGISTRATION_STATE_ROAMING) { - /* Better keeping it up to date */ - memcpy(&(ril_data.state.plmndata), plmndata, sizeof(struct ipc_net_current_plmn_response)); - - return; - } else { - if (ril_data.tokens.operator != RIL_TOKEN_NULL && ril_data.tokens.operator != RIL_TOKEN_DATA_WAITING) { - RIL_LOGE("Another Operator Req is in progress, skipping"); - return; - } - - memcpy(&(ril_data.state.plmndata), plmndata, sizeof(struct ipc_net_current_plmn_response)); - - /* we already told RILJ to get the new data but it wasn't done yet */ - if (ril_tokens_net_get_data_waiting() && ril_data.tokens.operator == RIL_TOKEN_DATA_WAITING) { - RIL_LOGD("Updating Operator data in background"); - } else { - ril_tokens_net_set_data_waiting(); -#if RIL_VERSION >= 6 - ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); -#else - ril_request_unsolicited(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); -#endif - } - } - break; - case IPC_TYPE_RESP: - RIL_LOGD("Got SOL Operator message"); - - // IPC_NET_REGISTRATION_STATE_ROAMING is the biggest valid value - if (ril_data.state.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_NONE || - ril_data.state.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_SEARCHING || - ril_data.state.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_UNKNOWN || - ril_data.state.netinfo.reg_state > IPC_NET_REGISTRATION_STATE_ROAMING) { - /* Better keeping it up to date */ - memcpy(&(ril_data.state.plmndata), plmndata, sizeof(struct ipc_net_current_plmn_response)); - - ril_request_complete(t, RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW, NULL, 0); - - if (ril_data.tokens.operator != RIL_TOKEN_DATA_WAITING) - ril_data.tokens.operator = RIL_TOKEN_NULL; - return; - } else { - if (ril_data.tokens.operator != t) - RIL_LOGE("Operator tokens mismatch"); - - /* Better keeping it up to date */ - memcpy(&(ril_data.state.plmndata), plmndata, sizeof(struct ipc_net_current_plmn_response)); - - ril_plmn_string(plmndata->plmn, response); - - ril_request_complete(t, RIL_E_SUCCESS, response, sizeof(response)); - - for (i = 0; i < sizeof(response) / sizeof(char *) ; i++) { - if (response[i] != NULL) - free(response[i]); - } - - if (ril_data.tokens.operator != RIL_TOKEN_DATA_WAITING) - ril_data.tokens.operator = RIL_TOKEN_NULL; - } - break; - default: - RIL_LOGE("%s: unhandled ipc method: %d", __func__, info->type); - break; - } - - ril_tokens_net_state_dump(); - - return; - -error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -#if RIL_VERSION >= 6 -void ril_request_voice_registration_state(RIL_Token t) -#else -void ril_request_registration_state(RIL_Token t) -#endif -{ - struct ipc_net_regist_get regist_req; - char *response[4]; - int i; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - if (ril_data.tokens.registration_state == RIL_TOKEN_DATA_WAITING) { - RIL_LOGD("Got RILJ request for UNSOL data"); - - /* Send back the data we got UNSOL */ - ipc2ril_reg_state_resp(&(ril_data.state.netinfo), response); - - ril_request_complete(t, RIL_E_SUCCESS, response, sizeof(response)); - - for (i = 0; i < (int) (sizeof(response) / sizeof(char *)) ; i++) { - if (response[i] != NULL) - free(response[i]); - } - - ril_data.tokens.registration_state = RIL_TOKEN_NULL; - } else if (ril_data.tokens.registration_state == RIL_TOKEN_NULL) { - RIL_LOGD("Got RILJ request for SOL data"); - /* Request data to the modem */ - ril_data.tokens.registration_state = t; - - ipc_net_regist_get_setup(®ist_req, IPC_NET_SERVICE_DOMAIN_GSM); - ipc_fmt_send(IPC_NET_REGIST, IPC_TYPE_GET, (void *)®ist_req, sizeof(struct ipc_net_regist_get), ril_request_get_id(t)); - } else { - RIL_LOGE("Another request is going on, returning UNSOL data"); - - /* Send back the data we got UNSOL */ - ipc2ril_reg_state_resp(&(ril_data.state.netinfo), response); - - ril_request_complete(t, RIL_E_SUCCESS, response, sizeof(response)); - - for (i = 0; i < (int) (sizeof(response) / sizeof(char *)) ; i++) { - if (response[i] != NULL) - free(response[i]); - } - } - - ril_tokens_net_state_dump(); -} - -#if RIL_VERSION >= 6 -void ril_request_data_registration_state(RIL_Token t) -#else -void ril_request_gprs_registration_state(RIL_Token t) -#endif -{ - struct ipc_net_regist_get regist_req; - char *response[4]; - size_t i; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - if (ril_data.tokens.gprs_registration_state == RIL_TOKEN_DATA_WAITING) { - RIL_LOGD("Got RILJ request for UNSOL data"); - - /* Send back the data we got UNSOL */ - ipc2ril_gprs_reg_state_resp(&(ril_data.state.gprs_netinfo), response); - - ril_request_complete(t, RIL_E_SUCCESS, response, sizeof(response)); - - for (i = 0; i < sizeof(response) / sizeof(char *) ; i++) { - if (response[i] != NULL) - free(response[i]); - } - - ril_data.tokens.gprs_registration_state = RIL_TOKEN_NULL; - } else if (ril_data.tokens.gprs_registration_state == RIL_TOKEN_NULL) { - RIL_LOGD("Got RILJ request for SOL data"); - - /* Request data to the modem */ - ril_data.tokens.gprs_registration_state = t; - - ipc_net_regist_get_setup(®ist_req, IPC_NET_SERVICE_DOMAIN_GPRS); - ipc_fmt_send(IPC_NET_REGIST, IPC_TYPE_GET, (void *)®ist_req, sizeof(struct ipc_net_regist_get), ril_request_get_id(t)); - } else { - RIL_LOGE("Another request is going on, returning UNSOL data"); - - /* Send back the data we got UNSOL */ - ipc2ril_gprs_reg_state_resp(&(ril_data.state.gprs_netinfo), response); - - ril_request_complete(t, RIL_E_SUCCESS, response, sizeof(response)); - - for (i = 0; i < sizeof(response) / sizeof(char *) ; i++) { - if (response[i] != NULL) - free(response[i]); - } - } - - ril_tokens_net_state_dump(); -} - -void ipc_net_regist_unsol(struct ipc_message_info *info) -{ - struct ipc_net_regist_response *netinfo; - - if (info->data == NULL || info->length < sizeof(struct ipc_net_regist_response)) - goto error; - - netinfo = (struct ipc_net_regist_response *) info->data; - - RIL_LOGD("Got UNSOL NetRegist message"); - - switch (netinfo->domain) { - case IPC_NET_SERVICE_DOMAIN_GSM: - if (ril_data.tokens.registration_state != RIL_TOKEN_NULL && ril_data.tokens.registration_state != RIL_TOKEN_DATA_WAITING) { - RIL_LOGE("Another NetRegist Req is in progress, skipping"); - return; - } - - memcpy(&(ril_data.state.netinfo), netinfo, sizeof(struct ipc_net_regist_response)); - - /* we already told RILJ to get the new data but it wasn't done yet */ - if (ril_tokens_net_get_data_waiting() && ril_data.tokens.registration_state == RIL_TOKEN_DATA_WAITING) { - RIL_LOGD("Updating NetRegist data in background"); - } else { - ril_tokens_net_set_data_waiting(); -#if RIL_VERSION >= 6 - ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); -#else - ril_request_unsolicited(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); -#endif - } - break; - - case IPC_NET_SERVICE_DOMAIN_GPRS: - if (ril_data.tokens.gprs_registration_state != RIL_TOKEN_NULL && ril_data.tokens.gprs_registration_state != RIL_TOKEN_DATA_WAITING) { - RIL_LOGE("Another GPRS NetRegist Req is in progress, skipping"); - return; - } - - memcpy(&(ril_data.state.gprs_netinfo), netinfo, sizeof(struct ipc_net_regist_response)); - - /* we already told RILJ to get the new data but it wasn't done yet */ - if (ril_tokens_net_get_data_waiting() && ril_data.tokens.gprs_registration_state == RIL_TOKEN_DATA_WAITING) { - RIL_LOGD("Updating GPRSNetRegist data in background"); - } else { - ril_tokens_net_set_data_waiting(); -#if RIL_VERSION >= 6 - ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); -#else - ril_request_unsolicited(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); -#endif - } - break; - default: - RIL_LOGE("%s: unhandled service domain: %d", __func__, netinfo->domain); - break; - } - - ril_tokens_net_state_dump(); - - return; - -error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_net_regist_sol(struct ipc_message_info *info) -{ - struct ipc_net_regist_response *netinfo; - RIL_Token t; - - char *response[4]; - size_t i; - - if (info->data == NULL || info->length < sizeof(struct ipc_net_regist_response)) - goto error; - - netinfo = (struct ipc_net_regist_response *) info->data; - t = ril_request_get_token(info->aseq); - - RIL_LOGD("Got SOL NetRegist message"); - - switch (netinfo->domain) { - case IPC_NET_SERVICE_DOMAIN_GSM: - if (ril_data.tokens.registration_state != t) - RIL_LOGE("Registration state tokens mismatch"); - - /* Better keeping it up to date */ - memcpy(&(ril_data.state.netinfo), netinfo, sizeof(struct ipc_net_regist_response)); - - ipc2ril_reg_state_resp(netinfo, response); - - ril_request_complete(t, RIL_E_SUCCESS, response, sizeof(response)); - - for (i = 0; i < sizeof(response) / sizeof(char *) ; i++) { - if (response[i] != NULL) - free(response[i]); - } - - if (ril_data.tokens.registration_state != RIL_TOKEN_DATA_WAITING) - ril_data.tokens.registration_state = RIL_TOKEN_NULL; - break; - case IPC_NET_SERVICE_DOMAIN_GPRS: - if (ril_data.tokens.gprs_registration_state != t) - RIL_LOGE("GPRS registration state tokens mismatch"); - - /* Better keeping it up to date */ - memcpy(&(ril_data.state.gprs_netinfo), netinfo, sizeof(struct ipc_net_regist_response)); - - ipc2ril_gprs_reg_state_resp(netinfo, response); - - ril_request_complete(t, RIL_E_SUCCESS, response, sizeof(response)); - - for (i = 0; i < sizeof(response) / sizeof(char *) ; i++) { - if (response[i] != NULL) - free(response[i]); - } - if (ril_data.tokens.registration_state != RIL_TOKEN_DATA_WAITING) - ril_data.tokens.gprs_registration_state = RIL_TOKEN_NULL; - break; - default: - RIL_LOGE("%s: unhandled service domain: %d", __func__, netinfo->domain); - break; - } - - ril_tokens_net_state_dump(); - - return; - -error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_net_regist(struct ipc_message_info *info) -{ - if (info == NULL) - return; - - if (ril_radio_state_complete(RADIO_STATE_OFF, RIL_TOKEN_NULL)) - return; - - switch (info->type) { - case IPC_TYPE_NOTI: - ipc_net_regist_unsol(info); - break; - case IPC_TYPE_RESP: - ipc_net_regist_sol(info); - break; - default: - RIL_LOGE("%s: unhandled ipc method: %d", __func__, info->type); - break; - } - -} - -void ril_request_query_available_networks(RIL_Token t) -{ - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - ipc_fmt_send_get(IPC_NET_PLMN_LIST, ril_request_get_id(t)); -} - -void ipc_net_plmn_list(struct ipc_message_info *info) -{ - struct ipc_net_plmn_entries *entries_info; - struct ipc_net_plmn_entry *entries; - - char **response; - int length; - int count; - - int index; - int i; - - if (info->data == NULL || info->length < sizeof(struct ipc_net_plmn_entries)) - goto error; - - entries_info = (struct ipc_net_plmn_entries *) info->data; - entries = (struct ipc_net_plmn_entry *) (info->data + sizeof(struct ipc_net_plmn_entries)); - - RIL_LOGD("Listed %d PLMNs\n", entries_info->num); - - length = sizeof(char *) * 4 * entries_info->num; - response = (char **) calloc(1, length); - - count = 0; - for (i = 0 ; i < entries_info->num ; i++) { - // Assumed type for 'emergency only' PLMNs - if (entries[i].type == 0x01) - continue; - - index = count * 4; - ril_plmn_string(entries[i].plmn, &response[index]); - - index = count * 4 + 3; - switch (entries[i].status) { - case IPC_NET_PLMN_STATUS_AVAILABLE: - response[index] = strdup("available"); - break; - case IPC_NET_PLMN_STATUS_CURRENT: - response[index] = strdup("current"); - break; - case IPC_NET_PLMN_STATUS_FORBIDDEN: - response[index] = strdup("forbidden"); - break; - default: - response[index] = strdup("unknown"); - break; - } - - count++; - } - - length = sizeof(char *) * 4 * count; - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, response, length); - - for (i = 0 ; i < entries_info->num ; i++) - if (response[i] != NULL) - free(response[i]); - - free(response); - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_get_preferred_network_type(RIL_Token t) -{ - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - ipc_fmt_send_get(IPC_NET_MODE_SEL, ril_request_get_id(t)); -} - -void ril_request_set_preferred_network_type(RIL_Token t, void *data, size_t length) -{ - int ril_mode; - struct ipc_net_mode_sel mode_sel; - - if (data == NULL || length < (int) sizeof(int)) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - ril_mode = *((int *) data); - - mode_sel.mode_sel = ril2ipc_mode_sel(ril_mode); - - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_NET_MODE_SEL); - - ipc_fmt_send(IPC_NET_MODE_SEL, IPC_TYPE_SET, (unsigned char *) &mode_sel, sizeof(mode_sel), ril_request_get_id(t)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_net_mode_sel(struct ipc_message_info *info) -{ - struct ipc_net_mode_sel *mode_sel; - int ril_mode; - - if (info->data == NULL || info->length < sizeof(struct ipc_net_mode_sel)) - goto error; - - mode_sel = (struct ipc_net_mode_sel *) info->data; - ril_mode = ipc2ril_mode_sel(mode_sel->mode_sel); - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, &ril_mode, sizeof(ril_mode)); - - return; - -error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_query_network_selection_mode(RIL_Token t) -{ - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - ipc_fmt_send_get(IPC_NET_PLMN_SEL, ril_request_get_id(t)); -} - -void ipc_net_plmn_sel(struct ipc_message_info *info) -{ - struct ipc_net_plmn_sel_get *plmn_sel; - int ril_mode; - - if (info->data == NULL || info->length < sizeof(struct ipc_net_plmn_sel_get)) - goto error; - - plmn_sel = (struct ipc_net_plmn_sel_get *) info->data; - ril_mode = ipc2ril_plmn_sel(plmn_sel->plmn_sel); - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, &ril_mode, sizeof(ril_mode)); - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_net_plmn_sel_complete(struct ipc_message_info *info) -{ - struct ipc_gen_phone_res *phone_res; - int rc; - - phone_res = (struct ipc_gen_phone_res *) info->data; - - rc = ipc_gen_phone_res_check(phone_res); - if (rc < 0) { - if ((phone_res->code & 0x00ff) == 0x6f) { - RIL_LOGE("Not authorized to register to this network!"); - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_ILLEGAL_SIM_OR_ME, NULL, 0); - } else { - RIL_LOGE("There was an error during operator selection!"); - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - } - return; - } - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, NULL, 0); -} - -void ril_request_set_network_selection_automatic(RIL_Token t) -{ - struct ipc_net_plmn_sel_set plmn_sel; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - ipc_net_plmn_sel_set_setup(&plmn_sel, IPC_NET_PLMN_SEL_AUTO, NULL, IPC_NET_ACCESS_TECHNOLOGY_UNKNOWN); - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_NET_PLMN_SEL, ipc_net_plmn_sel_complete); - - ipc_fmt_send(IPC_NET_PLMN_SEL, IPC_TYPE_SET, (unsigned char *) &plmn_sel, sizeof(plmn_sel), ril_request_get_id(t)); -} - -void ril_request_set_network_selection_manual(RIL_Token t, void *data, size_t length) -{ - struct ipc_net_plmn_sel_set plmn_sel; - - if (data == NULL || length < (int) sizeof(char *)) - return; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - // FIXME: We always assume UMTS capability - ipc_net_plmn_sel_set_setup(&plmn_sel, IPC_NET_PLMN_SEL_MANUAL, data, IPC_NET_ACCESS_TECHNOLOGY_UMTS); - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_NET_PLMN_SEL, ipc_net_plmn_sel_complete); - - ipc_fmt_send(IPC_NET_PLMN_SEL, IPC_TYPE_SET, (unsigned char *) &plmn_sel, sizeof(plmn_sel), ril_request_get_id(t)); -} diff --git a/network.c b/network.c new file mode 100644 index 0000000..6c70774 --- /dev/null +++ b/network.c @@ -0,0 +1,1168 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> + * + * Based on the CyanogenMod Smdk4210RIL implementation: + * Copyright (C) 2011 The CyanogenMod Project + * + * Samsung-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. + * + * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <ctype.h> + +#define LOG_TAG "RIL" +#include <utils/Log.h> + +#include <samsung-ril.h> +#include <utils.h> +#include <plmn_list.h> + +#if RIL_VERSION >= 6 +int ipc2ril_disp_rssi(unsigned char rssi, RIL_SignalStrength_v6 *strength) +#else +int ipc2ril_disp_rssi(unsigned char rssi, RIL_SignalStrength *strength) +#endif +{ + int asu; + + if (strength == NULL) + return -1; + +#if RIL_VERSION >= 6 + memset(strength, -1, sizeof(RIL_SignalStrength_v6)); +#else + memset(strength, -1, sizeof(RIL_SignalStrength)); +#endif + + asu = (int) rssi / -2 + 56; + + if (asu < 0) + asu = 0; + else if (asu > 31) + asu = 31; + + strength->GW_SignalStrength.signalStrength = asu; + strength->GW_SignalStrength.bitErrorRate = 99; + + RIL_LOGD("Signal strength is %d", strength->GW_SignalStrength.signalStrength); + + return 0; +} + +#if RIL_VERSION >= 6 +int ipc2ril_disp_icon_info(struct ipc_disp_icon_info_response_data *data, + RIL_SignalStrength_v6 *strength) +#else +int ipc2ril_disp_icon_info(struct ipc_disp_icon_info_response_data *data, + RIL_SignalStrength *strength) +#endif +{ + int asu_bars[] = { 1, 3, 5, 8, 12, 15 }; + unsigned int asu_bars_count = sizeof(asu_bars) / sizeof(int); + unsigned char asu_bars_index; + int rc; + + if (data == NULL || strength == NULL) + return -1; + + if (!(data->flags & IPC_DISP_ICON_INFO_FLAG_RSSI)) + return -1; + +#if RIL_VERSION >= 6 + memset(strength, -1, sizeof(RIL_SignalStrength_v6)); +#else + memset(strength, -1, sizeof(RIL_SignalStrength)); +#endif + + asu_bars_index = data->rssi; + if (asu_bars_index >= asu_bars_count) + asu_bars_index = asu_bars_count - 1; + + strength->GW_SignalStrength.signalStrength = asu_bars[asu_bars_index]; + + strength->GW_SignalStrength.bitErrorRate = 99; + + RIL_LOGD("Signal strength is %d", strength->GW_SignalStrength.signalStrength); + + return 0; +} + +#if RIL_VERSION >= 6 +int ipc2ril_disp_rssi_info(struct ipc_disp_rssi_info_data *data, + RIL_SignalStrength_v6 *strength) +#else +int ipc2ril_disp_rssi_info(struct ipc_disp_rssi_info_data *data, + RIL_SignalStrength *strength) +#endif +{ + int rc; + + if (data == NULL) + return -1; + + rc = ipc2ril_disp_rssi(data->rssi, strength); + if (rc < 0) + return -1; + + return 0; +} + +int ipc2ril_net_plmn_sel(struct ipc_net_plmn_sel_response_data *data) +{ + if (data == NULL) + return -1; + + switch (data->plmn_sel) { + case IPC_NET_PLMN_SEL_AUTO: + return 0; + case IPC_NET_PLMN_SEL_MANUAL: + return 1; + default: + return -1; + } +} + +int ipc2ril_net_regist_response(struct ipc_net_regist_response_data *data, + unsigned char hsdpa_status, char **registration, + size_t registration_size) +{ +#if RIL_VERSION >= 6 + RIL_RadioTechnology act; +#else + int act; +#endif + unsigned char status; + + if (data == NULL || registration == NULL) + return -1; + + memset(registration, 0, registration_size); + +#if RIL_VERSION >= 6 + switch (data->act) { + case IPC_NET_ACCESS_TECHNOLOGY_GSM: + case IPC_NET_ACCESS_TECHNOLOGY_GSM2: +#if RIL_VERSION >= 7 + act = RADIO_TECH_GSM; +#else + act = RADIO_TECH_UNKNOWN; +#endif + break; + case IPC_NET_ACCESS_TECHNOLOGY_GPRS: + act = RADIO_TECH_GPRS; + break; + case IPC_NET_ACCESS_TECHNOLOGY_EDGE: + act = RADIO_TECH_EDGE; + break; + case IPC_NET_ACCESS_TECHNOLOGY_UMTS: + switch (hsdpa_status) { + case IPC_GPRS_HSDPA_STATUS_HSDPA: + act = RADIO_TECH_HSDPA; + break; + case IPC_GPRS_HSDPA_STATUS_HSPAP: + act = RADIO_TECH_HSPAP; + break; + default: + act = RADIO_TECH_UMTS; + break; + } + break; + default: + act = RADIO_TECH_UNKNOWN; + break; + } +#else + switch (data->act) { + case IPC_NET_ACCESS_TECHNOLOGY_GSM: + case IPC_NET_ACCESS_TECHNOLOGY_GSM2: + act = 0; + break; + case IPC_NET_ACCESS_TECHNOLOGY_GPRS: + act = 1; + break; + case IPC_NET_ACCESS_TECHNOLOGY_EDGE: + act = 2; + break; + case IPC_NET_ACCESS_TECHNOLOGY_UMTS: + switch (hsdpa_status) { + case IPC_GPRS_HSDPA_STATUS_HSDPA: + case IPC_GPRS_HSDPA_STATUS_HSPAP: + act = 9; + break; + default: + act = 3; + break; + } + break; + default: + act = 0; + break; + } +#endif + + switch (data->status) { + case IPC_NET_REGISTRATION_STATUS_NONE: + status = 0; + break; + case IPC_NET_REGISTRATION_STATUS_HOME: + status = 1; + break; + case IPC_NET_REGISTRATION_STATUS_SEARCHING: + status = 2; + break; + case IPC_NET_REGISTRATION_STATUS_EMERGENCY: + status = 10; + break; + case IPC_NET_REGISTRATION_STATUS_UNKNOWN: + status = 4; + break; + case IPC_NET_REGISTRATION_STATUS_ROAMING: + status = 5; + break; + default: + status = 0; + break; + } + + asprintf(®istration[0], "%d", status); + asprintf(®istration[1], "%x", data->lac); + asprintf(®istration[2], "%x", data->cid); + asprintf(®istration[3], "%d", act); + + return 0; +} + +int ipc2ril_net_operator(char *data, size_t size, char **plmn, + char **operator_long, char **operator_short) +{ + char buffer[7] = { 0 }; + unsigned int mcc = 0; + unsigned int mnc = 0; + unsigned int count; + unsigned int i; + int rc; + + if (data == NULL || size == 0 || plmn == NULL) + return -1; + + *plmn = NULL; + + count = size / sizeof(char); + + for (i = 0; i < count; i++) { + if (!isdigit(data[i])) { + buffer[i] = '\0'; + break; + } + + buffer[i] = data[i]; + } + + if (buffer[0] == '\0') + goto error; + + *plmn = strdup(buffer); + + if (operator_long == NULL || operator_short == NULL) { + rc = 0; + goto complete; + } + + *operator_long = NULL; + *operator_short = NULL; + + rc = sscanf((char *) &buffer, "%3u%2u", &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; + } + + 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; +} + +int ipc2ril_net_serving_network(struct ipc_net_serving_network_data *data, + char **operator) +{ + int rc; + + if (operator == NULL) + return -1; + + rc = ipc2ril_net_operator((char *) &data->plmn, sizeof(data->plmn), &operator[2], &operator[0], &operator[1]); + if (rc < 0) + return -1; + + return 0; +} + +#if RIL_VERSION >= 6 +RIL_PreferredNetworkType ipc2ril_net_mode_sel(struct ipc_net_mode_sel_data *data) +#else +int ipc2ril_net_mode_sel(struct ipc_net_mode_sel_data *data) +#endif +{ + if (data == NULL) + return -1; + +#if RIL_VERSION >= 6 + switch (data->mode_sel) { + case IPC_NET_MODE_SEL_GSM_UMTS: + return PREF_NET_TYPE_GSM_WCDMA; + case IPC_NET_MODE_SEL_GSM_ONLY: + return PREF_NET_TYPE_GSM_ONLY; + case IPC_NET_MODE_SEL_UMTS_ONLY: + return PREF_NET_TYPE_WCDMA; + default: + return -1; + } +#else + switch (data->mode_sel) { + case IPC_NET_MODE_SEL_GSM_UMTS: + return 0; + case IPC_NET_MODE_SEL_GSM_ONLY: + return 1; + case IPC_NET_MODE_SEL_UMTS_ONLY: + return 2; + default: + return -1; + } +#endif +} + +#if RIL_VERSION >= 6 +unsigned char ril2ipc_net_mode_sel(RIL_PreferredNetworkType type) +#else +unsigned char ril2ipc_net_mode_sel(int type) +#endif +{ +#if RIL_VERSION >= 6 + switch (type) { + case PREF_NET_TYPE_GSM_WCDMA: + case PREF_NET_TYPE_GSM_WCDMA_AUTO: + return IPC_NET_MODE_SEL_GSM_UMTS; + case PREF_NET_TYPE_GSM_ONLY: + return IPC_NET_MODE_SEL_GSM_ONLY; + case PREF_NET_TYPE_WCDMA: + return IPC_NET_MODE_SEL_UMTS_ONLY; + default: + return IPC_NET_MODE_SEL_GSM_UMTS; + } +#else + switch (type) { + case 0: + case 3: + return IPC_NET_MODE_SEL_GSM_UMTS; + case 1: + return IPC_NET_MODE_SEL_GSM_ONLY; + case 2: + return IPC_NET_MODE_SEL_UMTS_ONLY; + default: + return IPC_NET_MODE_SEL_GSM_UMTS; + } +#endif +} + +int ipc_disp_icon_info(struct ipc_message *message) +{ + struct ipc_disp_icon_info_response_data *data; +#if RIL_VERSION >= 6 + RIL_SignalStrength_v6 strength; +#else + RIL_SignalStrength strength; +#endif + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_disp_icon_info_response_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + data = (struct ipc_disp_icon_info_response_data *) message->data; + + rc = ipc2ril_disp_icon_info(data, &strength); + if (rc < 0) { + if (message->type == IPC_TYPE_RESP && ipc_seq_valid(message->aseq)) + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + + return 0; + } + + if (message->type == IPC_TYPE_RESP && ipc_seq_valid(message->aseq)) + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &strength, sizeof(strength)); + else + ril_request_unsolicited(RIL_UNSOL_SIGNAL_STRENGTH, (void *) &strength, sizeof(strength)); + + return 0; +} + +int ril_request_signal_strength(void *data, size_t size, RIL_Token token) +{ + struct ipc_disp_icon_info_request_data request_data; + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + memset(&request_data, 0, sizeof(request_data)); + request_data.flags = IPC_DISP_ICON_INFO_FLAG_RSSI; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_DISP_ICON_INFO, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + return RIL_REQUEST_HANDLED; +} + +int ipc_disp_rssi_info(struct ipc_message *message) +{ + struct ipc_disp_rssi_info_data *data; +#if RIL_VERSION >= 6 + RIL_SignalStrength_v6 strength; +#else + RIL_SignalStrength strength; +#endif + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_disp_rssi_info_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + data = (struct ipc_disp_rssi_info_data *) message->data; + + rc = ipc2ril_disp_rssi_info(data, &strength); + if (rc < 0) + return 0; + + ril_request_unsolicited(RIL_UNSOL_SIGNAL_STRENGTH, (void *) &strength, sizeof(strength)); + + return 0; +} + +int ipc_net_plmn_sel(struct ipc_message *message) +{ + struct ipc_net_plmn_sel_response_data *data; + int selection; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_net_plmn_sel_response_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; + + data = (struct ipc_net_plmn_sel_response_data *) message->data; + + selection = ipc2ril_net_plmn_sel(data); + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &selection, sizeof(selection)); + + return 0; +} + +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; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_NET_PLMN_SEL, IPC_TYPE_GET, NULL, 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + return RIL_REQUEST_HANDLED; +} + +int ipc_net_plmn_sel_callback(struct ipc_message *message) +{ + struct ipc_gen_phone_res_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; + + data = (struct ipc_gen_phone_res_data *) message->data; + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) { + if ((data->code & 0xff) == 0x6f) { + RIL_LOGE("%s: Unauthorized network selection", __func__); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_ILLEGAL_SIM_OR_ME, NULL, 0); + } else { + RIL_LOGE("%s: Network selection failed", __func__); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + } + } else { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); + } + + return 0; +} + +int ril_request_set_network_selection_automatic(void *data, size_t size, + RIL_Token token) +{ + struct ipc_net_plmn_sel_request_data request_data; + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + rc = ipc_net_plmn_sel_setup(&request_data, IPC_NET_PLMN_SEL_AUTO, NULL, IPC_NET_ACCESS_TECHNOLOGY_UNKNOWN); + if (rc < 0) + goto error; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_NET_PLMN_SEL, ipc_net_plmn_sel_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_NET_PLMN_SEL, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_set_network_selection_manual(void *data, size_t size, + RIL_Token token) +{ + struct ipc_net_plmn_sel_request_data request_data; + int rc; + + if (data == NULL || size < sizeof(char)) { + 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; + + rc = ipc_net_plmn_sel_setup(&request_data, IPC_NET_PLMN_SEL_MANUAL, (const char *) data, IPC_NET_ACCESS_TECHNOLOGY_UNKNOWN); + if (rc < 0) + goto error; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_NET_PLMN_SEL, ipc_net_plmn_sel_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_NET_PLMN_SEL, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_net_serving_network(struct ipc_message *message) +{ + struct ipc_net_serving_network_data *data; + char *operator[3] = { NULL }; + unsigned char count; + unsigned int i; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_net_regist_response_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + data = (struct ipc_net_serving_network_data *) message->data; + + rc = ipc2ril_net_serving_network(data, (char **) &operator); + if (rc < 0) { + if (message->type == IPC_TYPE_RESP && ipc_seq_valid(message->aseq)) + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + + return 0; + } + + count = sizeof(operator) / sizeof(char *); + + if (message->type == IPC_TYPE_RESP && ipc_seq_valid(message->aseq)) { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &operator, sizeof(operator)); + + for (i = 0; i < count; i++) { + if (operator[i] != NULL) + free(operator[i]); + } + } else { + ril_request_data_set(RIL_REQUEST_OPERATOR, (void *) operator, sizeof(operator)); +#if RIL_VERSION >= 6 + ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); +#else + ril_request_unsolicited(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); +#endif + } + + return 0; +} + +int ril_request_operator(void *data, size_t size, RIL_Token token) +{ + struct ril_request *request; + void *operator_data; + size_t operator_size; + char **operator; + unsigned char count; + unsigned int i; + 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; + + operator_size = ril_request_data_size_get(RIL_REQUEST_OPERATOR); + operator_data = ril_request_data_get(RIL_REQUEST_OPERATOR); + + if (operator_data != NULL && operator_size > 0) { + ril_request_complete(token, RIL_E_SUCCESS, operator_data, operator_size); + + count = operator_size / sizeof(char *); + operator = (char **) operator_data; + + for (i = 0; i < count; i++) { + if (operator[i] != NULL) + free(operator[i]); + } + + free(operator_data); + + return RIL_REQUEST_COMPLETED; + } else { + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_NET_SERVING_NETWORK, IPC_TYPE_GET, NULL, 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + return RIL_REQUEST_HANDLED; + } +} + +int ipc_net_plmn_list(struct ipc_message *message) +{ + struct ipc_net_plmn_list_entry *entry; + char **networks = NULL; + size_t networks_size; + unsigned int networks_count = 0; + char **network; + unsigned char count; + unsigned char index; + unsigned int i; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_net_plmn_list_header)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; + + count = ipc_net_plmn_list_count_extract(message->data, message->size); + if (count == 0) { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); + return 0; + } + + networks_size = count * 4 * sizeof(char *); + networks = calloc(1, networks_size); + + for (index = 0; index < count; index++) { + entry = ipc_net_plmn_list_entry_extract(message->data, message->size, index); + if (entry == NULL) + goto error; + + network = (char **) ((unsigned char *) networks + networks_count * 4 * sizeof(char *)); + + rc = ipc2ril_net_operator(entry->plmn, sizeof(entry->plmn), &network[2], &network[0], &network[1]); + if (rc < 0) + goto error; + + switch (entry->status) { + case IPC_NET_PLMN_STATUS_AVAILABLE: + network[3] = strdup("available"); + break; + case IPC_NET_PLMN_STATUS_CURRENT: + network[3] = strdup("current"); + break; + case IPC_NET_PLMN_STATUS_FORBIDDEN: + network[3] = strdup("forbidden"); + break; + default: + network[3] = strdup("unknown"); + break; + } + + networks_count++; + } + + RIL_LOGD("Found %d available networks", networks_count); + + networks_size = networks_count * 4 * sizeof(char *); + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) networks, networks_size); + + goto complete; + +error: + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + +complete: + if (networks != NULL && networks_size > 0) { + for (index = 0; index < networks_count; index++) { + if (networks[index] != NULL) + free(networks[index]); + } + + free(networks); + } + + return 0; +} + +int ril_request_query_available_networks(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_QUERY_AVAILABLE_NETWORKS, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_NET_PLMN_LIST, IPC_TYPE_GET, NULL, 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + return RIL_REQUEST_HANDLED; +} + +int ipc_net_regist(struct ipc_message *message) +{ + struct ipc_net_regist_response_data *data; + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + struct ipc_client_gprs_capabilities gprs_capabilities; + char *voice_registration[15] = { NULL }; + char *data_registration[5] = { NULL }; + char **registration; + size_t registration_size; + unsigned int count; + unsigned int i; + int request; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_net_regist_response_data)) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return 0; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + data = (struct ipc_net_regist_response_data *) message->data; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + + if (data->domain == IPC_NET_SERVICE_DOMAIN_GSM) { +#if RIL_VERSION >= 6 + request = RIL_REQUEST_VOICE_REGISTRATION_STATE; +#else + request = RIL_REQUEST_REGISTRATION_STATE; +#endif + + registration = (char **) &voice_registration; + registration_size = sizeof(voice_registration); + count = registration_size / sizeof(char *); + } else if (data->domain == IPC_NET_SERVICE_DOMAIN_GPRS) { +#if RIL_VERSION >= 6 + request = RIL_REQUEST_DATA_REGISTRATION_STATE; +#else + request = RIL_REQUEST_GPRS_REGISTRATION_STATE; +#endif + + registration = (char **) &data_registration; + registration_size = sizeof(data_registration); + count = registration_size / sizeof(char *); + } else { + RIL_LOGD("%s: Invalid networking registration domain (0x%x)", __func__, data->domain); + return 0; + } + + rc = ipc2ril_net_regist_response(data, ipc_fmt_data->hsdpa_status_data.status, registration, registration_size); + if (rc < 0) + goto error; + + if (data->domain == IPC_NET_SERVICE_DOMAIN_GPRS) { + if (ipc_fmt_data->ipc_client == NULL) + goto error; + + rc = ipc_client_gprs_get_capabilities(ipc_fmt_data->ipc_client, &gprs_capabilities); + if (rc < 0) + goto error; + + asprintf(®istration[4], "%d", gprs_capabilities.cid_count); + } + + if (message->type == IPC_TYPE_RESP && ipc_seq_valid(message->aseq)) { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) registration, registration_size); + + for (i = 0; i < count; i++) { + if (registration[i] != NULL) + free(registration[i]); + } + + return 0; + } else { + ril_request_data_set(request, (void *) registration, registration_size); + +#if RIL_VERSION >= 6 + ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); +#else + ril_request_unsolicited(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); +#endif + } + + goto complete; + +error: + if (ipc_seq_valid(message->aseq)) + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + + for (i = 0; i < count; i++) { + if (registration[i] != NULL) + free(registration[i]); + } + +complete: + return 0; +} + +#if RIL_VERSION >= 6 +int ril_request_voice_registration_state(void *data, size_t size, + RIL_Token token) +#else +int ril_request_registration_state(void *data, size_t size, RIL_Token token) +#endif +{ + struct ipc_net_regist_request_data request_data; + struct ril_request *request; + void *registration_data; + size_t registration_size; + char **registration; + unsigned int count; + unsigned int i; + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + +#if RIL_VERSION >= 6 + request = ril_request_find_request_status(RIL_REQUEST_VOICE_REGISTRATION_STATE, RIL_REQUEST_HANDLED); +#else + request = ril_request_find_request_status(RIL_REQUEST_REGISTRATION_STATE, RIL_REQUEST_HANDLED); +#endif + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + +#if RIL_VERSION >= 6 + registration_size = ril_request_data_size_get(RIL_REQUEST_VOICE_REGISTRATION_STATE); + registration_data = ril_request_data_get(RIL_REQUEST_VOICE_REGISTRATION_STATE); +#else + registration_size = ril_request_data_size_get(RIL_REQUEST_REGISTRATION_STATE); + registration_data = ril_request_data_get(RIL_REQUEST_REGISTRATION_STATE); +#endif + if (registration_data != NULL && registration_size > 0) { + ril_request_complete(token, RIL_E_SUCCESS, registration_data, registration_size); + + count = registration_size / sizeof(char *); + registration = (char **) registration_data; + + for (i = 0; i < count; i++) { + if (registration[i] != NULL) + free(registration[i]); + } + + free(registration_data); + + rc = RIL_REQUEST_COMPLETED; + } else { + rc = ipc_net_regist_setup(&request_data, IPC_NET_SERVICE_DOMAIN_GSM); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_NET_REGIST, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + } + + goto complete; + +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +#if RIL_VERSION >= 6 +int ril_request_data_registration_state(void *data, size_t size, + RIL_Token token) +#else +int ril_request_gprs_registration_state(void *data, size_t size, + RIL_Token token) +#endif +{ + struct ipc_net_regist_request_data request_data; + struct ril_request *request; + void *registration_data; + size_t registration_size; + char **registration; + unsigned int count; + unsigned int i; + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + +#if RIL_VERSION >= 6 + request = ril_request_find_request_status(RIL_REQUEST_DATA_REGISTRATION_STATE, RIL_REQUEST_HANDLED); +#else + request = ril_request_find_request_status(RIL_REQUEST_GPRS_REGISTRATION_STATE, RIL_REQUEST_HANDLED); +#endif + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + +#if RIL_VERSION >= 6 + registration_size = ril_request_data_size_get(RIL_REQUEST_DATA_REGISTRATION_STATE); + registration_data = ril_request_data_get(RIL_REQUEST_DATA_REGISTRATION_STATE); +#else + registration_size = ril_request_data_size_get(RIL_REQUEST_GPRS_REGISTRATION_STATE); + registration_data = ril_request_data_get(RIL_REQUEST_GPRS_REGISTRATION_STATE); +#endif + if (registration_data != NULL && registration_size > 0) { + ril_request_complete(token, RIL_E_SUCCESS, registration_data, registration_size); + + count = registration_size / sizeof(char *); + registration = (char **) registration_data; + + for (i = 0; i < count; i++) { + if (registration[i] != NULL) + free(registration[i]); + } + + free(registration_data); + + rc = RIL_REQUEST_COMPLETED; + } else { + rc = ipc_net_regist_setup(&request_data, IPC_NET_SERVICE_DOMAIN_GPRS); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_NET_REGIST, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + } + + goto complete; + +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_net_mode_sel(struct ipc_message *message) +{ + struct ipc_net_mode_sel_data *data; + int type; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_net_mode_sel_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; + + data = (struct ipc_net_mode_sel_data *) message->data; + + type = ipc2ril_net_mode_sel(data); + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &type, sizeof(type)); + + return 0; +} + +int ril_request_get_preferred_network_type(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; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_NET_MODE_SEL, IPC_TYPE_GET, NULL, 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + return RIL_REQUEST_HANDLED; +} + +int ril_request_set_preferred_network_type(void *data, size_t size, + RIL_Token token) +{ + struct ipc_net_mode_sel_data request_data; + int type; + int rc; + + if (data == NULL || size < sizeof(int)) + goto error; + + type = *((int *) data); + + memset(&request_data, 0, sizeof(request_data)); + request_data.mode_sel = ril2ipc_net_mode_sel(type); + + if (request_data.mode_sel == 0) { + ril_request_complete(token, RIL_E_MODE_NOT_SUPPORTED, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + goto complete; + } + + rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_NET_MODE_SEL); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_NET_MODE_SEL, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} @@ -0,0 +1,238 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr> + * + * Samsung-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. + * + * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> + +#define LOG_TAG "RIL" +#include <utils/Log.h> + +#include <samsung-ril.h> +#include <ril_oem.h> + +int ipc_svc_display_screen(struct ipc_message *message) +{ + struct ipc_svc_display_screen_entry *entry; + char svc_end_message[34] = " End service mode"; + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + struct ril_request *request; + void *screen_data = NULL; + size_t screen_size = 0; + unsigned char count; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_svc_display_screen_header)) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return 0; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + + count = ipc_svc_display_screen_count_extract(message->data, message->size); + + if (count > 0) { + if (!ipc_fmt_data->svc_session) + ipc_fmt_data->svc_session = 1; + + entry = ipc_svc_display_screen_extract(message->data, message->size, 0); + if (entry == NULL) + goto error; + + // Invalid messages have bogus first entry index + if (entry->index != 0) + goto complete; + + screen_size = count * sizeof(struct ipc_svc_display_screen_entry); + screen_data = (void *) entry; + } else { + if (ipc_fmt_data->svc_session) + ipc_fmt_data->svc_session = 0; + + ril_request_data_free(RIL_REQUEST_OEM_HOOK_RAW); + + screen_size = sizeof(svc_end_message); + screen_data = (void *) &svc_end_message; + } + + request = ril_request_find_request_status(RIL_REQUEST_OEM_HOOK_RAW, RIL_REQUEST_HANDLED); + if (request != NULL) + ril_request_complete(request->token, RIL_E_SUCCESS, screen_data, screen_size); + else + ril_request_data_set_uniq(RIL_REQUEST_OEM_HOOK_RAW, screen_data, screen_size); + + goto complete; + +error: + request = ril_request_find_request_status(RIL_REQUEST_OEM_HOOK_RAW, RIL_REQUEST_HANDLED); + if (request != NULL) + ril_request_complete(request->token, RIL_E_GENERIC_FAILURE, NULL, 0); + +complete: + return 0; +} + +int ril_request_oem_hook_raw(void *data, size_t size, RIL_Token token) +{ + struct ipc_svc_enter_data svc_enter_data; + struct ipc_svc_end_data svc_end_data; + struct ipc_svc_pro_keycode_data svc_pro_keycode_data; + RIL_OEMHookHeader *header; + RIL_OEMHookSvcEnterMode *svc_enter_mode; + RIL_OEMHookSvcEndMode *svc_end_mode; + RIL_OEMHookSvcKey *svc_key; + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + struct ril_request *request; + void *screen_data = NULL; + size_t screen_size = 0; + unsigned int length; + int rc; + + if (data == NULL || size < sizeof(RIL_OEMHookHeader)) + goto error; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + goto error; + + 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_OEM_HOOK_RAW, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + + header = (RIL_OEMHookHeader *) data; + + // Only SVC is supported + if (header->tag != RIL_OEM_HOOK_TAG_SVC) + goto error; + + length = size - sizeof(RIL_OEMHookHeader); + + switch (header->command) { + case RIL_OEM_COMMAND_SVC_ENTER_MODE: + if (length < sizeof(RIL_OEMHookSvcEnterMode)) + goto error; + + svc_enter_mode = (RIL_OEMHookSvcEnterMode *) ((unsigned char *) data + sizeof(RIL_OEMHookHeader)); + + if (svc_enter_mode->query) { + screen_size = ril_request_data_size_get(RIL_REQUEST_OEM_HOOK_RAW); + screen_data = ril_request_data_get(RIL_REQUEST_OEM_HOOK_RAW); + + ril_request_complete(token, RIL_E_SUCCESS, screen_data, screen_size); + + rc = RIL_REQUEST_COMPLETED; + goto complete; + } else { + rc = ipc_svc_enter_setup(&svc_enter_data, svc_enter_mode->mode, svc_enter_mode->type); + if (rc < 0) + goto error; + + rc = ipc_gen_phone_res_expect_abort(ipc_fmt_request_seq(token), IPC_SVC_ENTER); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SVC_ENTER, IPC_TYPE_SET, (void *) &svc_enter_data, sizeof(svc_enter_data)); + if (rc < 0) + goto error; + } + break; + case RIL_OEM_COMMAND_SVC_END_MODE: + if (length < sizeof(RIL_OEMHookSvcEndMode)) + goto error; + + svc_end_mode = (RIL_OEMHookSvcEndMode *) ((unsigned char *) data + sizeof(RIL_OEMHookHeader)); + + memset(&svc_end_data, 0, sizeof(svc_end_data)); + svc_end_data.mode = svc_end_mode->mode; + + rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_SVC_END); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SVC_END, IPC_TYPE_SET, (void *) &svc_end_data, sizeof(svc_end_data)); + if (rc < 0) + goto error; + + if (ipc_fmt_data->svc_session) + ipc_fmt_data->svc_session = 0; + + ril_request_data_free(RIL_REQUEST_OEM_HOOK_RAW); + break; + case RIL_OEM_COMMAND_SVC_KEY: + if (length < sizeof(RIL_OEMHookSvcKey)) + goto error; + + svc_key = (RIL_OEMHookSvcKey *) ((unsigned char *) data + sizeof(RIL_OEMHookHeader)); + + if (svc_key->query) { + screen_size = ril_request_data_size_get(RIL_REQUEST_OEM_HOOK_RAW); + screen_data = ril_request_data_get(RIL_REQUEST_OEM_HOOK_RAW); + + ril_request_complete(token, RIL_E_SUCCESS, screen_data, screen_size); + + rc = RIL_REQUEST_COMPLETED; + goto complete; + } else { + if (!ipc_fmt_data->svc_session) + goto error; + + memset(&svc_pro_keycode_data, 0, sizeof(svc_pro_keycode_data)); + svc_pro_keycode_data.key = svc_key->key; + + rc = ipc_gen_phone_res_expect_abort(ipc_fmt_request_seq(token), IPC_SVC_PRO_KEYCODE); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SVC_PRO_KEYCODE, IPC_TYPE_SET, (void *) &svc_pro_keycode_data, sizeof(svc_pro_keycode_data)); + if (rc < 0) + goto error; + } + break; + default: + goto error; + } + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + ril_request_data_free(RIL_REQUEST_OEM_HOOK_RAW); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + if (screen_data != NULL && screen_size > 0) + free(screen_data); + + return rc; +} @@ -0,0 +1,117 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> + * + * Samsung-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. + * + * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> + +#define LOG_TAG "RIL" +#include <utils/Log.h> + +#include <samsung-ril.h> +#include <utils.h> + +int ipc_pwr_phone_pwr_up(struct ipc_message *message) +{ + ril_radio_state_update(RADIO_STATE_OFF); + + return 0; +} + +int ipc_pwr_phone_reset(struct ipc_message *message) +{ + ril_radio_state_update(RADIO_STATE_OFF); + + return 0; +} + +int ipc_pwr_phone_state(struct ipc_message *message) +{ + struct ipc_pwr_phone_state_response_data *data; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_pwr_phone_state_response_data)) + return -1; + + if (!ipc_seq_valid(message->aseq)) + return 0; + + data = (struct ipc_pwr_phone_state_response_data *) message->data; + + switch (data->state) { + case IPC_PWR_PHONE_STATE_RESPONSE_LPM: + RIL_LOGD("Power state is low power mode"); + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); + ril_radio_state_update(RADIO_STATE_OFF); + break; + case IPC_PWR_PHONE_STATE_RESPONSE_NORMAL: + RIL_LOGD("Power state is normal"); + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); + ril_radio_state_update(RADIO_STATE_SIM_NOT_READY); + break; + } + + return 0; +} + +int ril_request_radio_power(void *data, size_t size, RIL_Token token) +{ + struct ipc_pwr_phone_state_request_data request_data; + struct ril_request *request; + int power_state; + 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); + + memset(&request_data, 0, sizeof(request_data)); + + if (power_state > 0) { + RIL_LOGD("Requesting normal power state"); + request_data.state = IPC_PWR_PHONE_STATE_REQUEST_NORMAL; + } else { + RIL_LOGD("Requesting low power mode power state"); + request_data.state = IPC_PWR_PHONE_STATE_REQUEST_LPM; + } + + rc = ipc_gen_phone_res_expect_abort(ipc_fmt_request_seq(token), IPC_PWR_PHONE_STATE); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} @@ -1,110 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#define LOG_TAG "RIL-PWR" -#include <utils/Log.h> - -#include "samsung-ril.h" -#include "util.h" - -/* - * Modem lets us know it's powered on. Though, it's still in LPM and should - * be considered as OFF. This request is used as a first indication that - * we can communicate with the modem, so unlock RIL start from here. - */ - -void ipc_pwr_phone_pwr_up(void) -{ - ril_radio_state_update(RADIO_STATE_OFF); -} - -void ipc_pwr_phone_reset(void) -{ - ril_radio_state_update(RADIO_STATE_OFF); -} - -void ipc_pwr_phone_state(struct ipc_message_info *info) -{ - unsigned char state; - - if (info->data == NULL || info->length < sizeof(unsigned char)) - return; - - state = *((unsigned char *) info->data); - - switch (state) { - case IPC_PWR_R(IPC_PWR_PHONE_STATE_LPM): - RIL_LOGD("Got power to LPM"); - - if (ril_data.tokens.radio_power != RIL_TOKEN_NULL) { - ril_request_complete(ril_data.tokens.radio_power, RIL_E_SUCCESS, NULL, 0); - ril_data.tokens.radio_power = RIL_TOKEN_NULL; - } - - ril_radio_state_update(RADIO_STATE_OFF); - break; - case IPC_PWR_R(IPC_PWR_PHONE_STATE_NORMAL): - RIL_LOGD("Got power to NORMAL"); - - if (ril_data.tokens.radio_power != RIL_TOKEN_NULL) { - ril_request_complete(ril_data.tokens.radio_power, RIL_E_SUCCESS, NULL, 0); - ril_data.tokens.radio_power = RIL_TOKEN_NULL; - } - - ril_radio_state_update(RADIO_STATE_SIM_NOT_READY); - break; - } - - ril_tokens_check(); -} - -void ril_request_radio_power(RIL_Token t, void *data, int length) -{ - int power_state; - unsigned short power_data; - - if (data == NULL || length < (int) sizeof(int)) - return; - - if (ril_radio_state_complete(RADIO_STATE_UNAVAILABLE, t)) - return; - - power_state = *((int *) data); - - RIL_LOGD("requested power_state is %d", power_state); - - if (power_state > 0) { - RIL_LOGD("Request power to NORMAL"); - power_data = IPC_PWR_PHONE_STATE_NORMAL; - - ipc_gen_phone_res_expect_to_abort(ril_request_get_id(t), IPC_PWR_PHONE_STATE); - ipc_fmt_send(IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, (void *) &power_data, sizeof(power_data), ril_request_get_id(t)); - - ril_data.tokens.radio_power = t; - } else { - RIL_LOGD("Request power to LPM"); - power_data = IPC_PWR_PHONE_STATE_LPM; - - ipc_gen_phone_res_expect_to_abort(ril_request_get_id(t), IPC_PWR_PHONE_STATE); - ipc_fmt_send(IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, (void *) &power_data, sizeof(power_data), ril_request_get_id(t)); - - ril_data.tokens.radio_power = t; - } -} @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,84 +17,132 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdlib.h> + #define LOG_TAG "RIL-RFS" #include <utils/Log.h> -#include "samsung-ril.h" -#include "util.h" +#include <samsung-ril.h> +#include <utils.h> -void ipc_rfs_nv_read_item(struct ipc_message_info *info) +int ipc_rfs_nv_read_item(struct ipc_message *message) { - struct ipc_client *ipc_client; + struct ipc_rfs_nv_read_item_response_header response_header; + struct ipc_rfs_nv_read_item_request_data *data; + struct ril_client *client; + struct ipc_rfs_data *ipc_rfs_data; + void *response_data = NULL; + size_t response_size = 0; + void *nv_data = NULL; + int rc; - struct ipc_rfs_io *rfs_io; - struct ipc_rfs_io_confirm *rfs_io_conf; + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_rfs_nv_read_item_request_data)) + return -1; - void *rfs_data; - int rc; + client = ril_client_find_id(RIL_CLIENT_IPC_RFS); + if (client == NULL || client->data == NULL) + return 0; + + ipc_rfs_data = (struct ipc_rfs_data *) client->data; + if (ipc_rfs_data->ipc_client == NULL) + return 0; + + data = (struct ipc_rfs_nv_read_item_request_data *) message->data; + + memset(&response_header, 0, sizeof(response_header)); - if (info->data == NULL || info->length < sizeof(struct ipc_rfs_io)) - return; + nv_data = ipc_nv_data_read(ipc_rfs_data->ipc_client, data->length, data->offset); + if (nv_data == NULL) { + RIL_LOGE("Reading %d nv_data bytes at offset 0x%x failed", data->length, data->offset); - rfs_io = (struct ipc_rfs_io *) info->data; + response_header.confirm = 0; - if (ril_data.ipc_rfs_client == NULL || ril_data.ipc_rfs_client->data == NULL) - return; + rc = ipc_rfs_send(message->aseq, IPC_RFS_NV_READ_ITEM, (void *) &response_header, sizeof(response_header)); + if (rc < 0) + goto complete; - ipc_client = (struct ipc_client *) ril_data.ipc_rfs_client->data; + goto complete; + } - rfs_io_conf = calloc(1, rfs_io->length + sizeof(struct ipc_rfs_io_confirm)); - rfs_data = rfs_io_conf + sizeof(struct ipc_rfs_io_confirm); + RIL_LOGD("Read %d nv_data bytes at offset 0x%x", data->length, data->offset); - RIL_LOGD("Asked to read 0x%x bytes at offset 0x%x", rfs_io->length, rfs_io->offset); - rc = nv_data_read(ipc_client, rfs_io->offset, rfs_io->length, rfs_data); + response_header.confirm = 1; + response_header.offset = data->offset; + response_header.length = data->length; - RIL_LOGD("Read rfs_data dump:"); - hex_dump(rfs_data, rfs_io->length > 0x100 ? 0x100 : rfs_io->length); + response_size = ipc_rfs_nv_data_item_size_setup(&response_header, nv_data, data->length); + if (response_size == 0) + goto complete; - RIL_LOGD("Sending RFS IO Confirm message (rc is %d)", rc); - rfs_io_conf->confirm = rc < 0 ? 0 : 1; - rfs_io_conf->offset = rfs_io->offset; - rfs_io_conf->length = rfs_io->length; + response_data = ipc_rfs_nv_read_item_setup(&response_header, nv_data, data->length); + if (response_data == NULL) + goto complete; - ipc_rfs_send(IPC_RFS_NV_READ_ITEM, (unsigned char *) rfs_io_conf, rfs_io->length + sizeof(struct ipc_rfs_io_confirm), info->aseq); + rc = ipc_rfs_send(message->aseq, IPC_RFS_NV_READ_ITEM, response_data, response_size); + if (rc < 0) + goto complete; - free(rfs_io_conf); + goto complete; + +complete: + if (response_data != NULL && response_size > 0) + free(response_data); + + if (nv_data != NULL) + free(nv_data); + + return 0; } -void ipc_rfs_nv_write_item(struct ipc_message_info *info) +int ipc_rfs_nv_write_item(struct ipc_message *message) { - struct ipc_client *ipc_client; + struct ipc_rfs_nv_write_item_request_header *header; + struct ipc_rfs_nv_write_item_response_data data; + struct ril_client *client; + struct ipc_rfs_data *ipc_rfs_data; + void *nv_data; + size_t nv_size; + int rc; - struct ipc_rfs_io *rfs_io; - struct ipc_rfs_io_confirm rfs_io_conf; + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_rfs_nv_write_item_request_header)) + return -1; - void *rfs_data; - int rc; + client = ril_client_find_id(RIL_CLIENT_IPC_RFS); + if (client == NULL || client->data == NULL) + return 0; + + ipc_rfs_data = (struct ipc_rfs_data *) client->data; + if (ipc_rfs_data->ipc_client == NULL) + return 0; - if (info->data == NULL || info->length < sizeof(struct ipc_rfs_io)) - return; + header = (struct ipc_rfs_nv_write_item_request_header *) message->data; - rfs_io = (struct ipc_rfs_io *) info->data; + nv_size = ipc_rfs_nv_write_item_size_extract(message->data, message->size); + if (nv_size == 0) + return 0; - if (ril_data.ipc_rfs_client == NULL || ril_data.ipc_rfs_client->data == NULL) - return; + nv_data = ipc_rfs_nv_write_item_extract(message->data, message->size); + if (nv_data == NULL) + return 0; - ipc_client = (struct ipc_client *) ril_data.ipc_rfs_client->data; + memset(&data, 0, sizeof(data)); - memset(&rfs_io_conf, 0, sizeof(rfs_io_conf)); - rfs_data = info->data + sizeof(struct ipc_rfs_io); + rc = ipc_nv_data_write(ipc_rfs_data->ipc_client, nv_data, header->length, header->offset); + if (rc < 0) { + RIL_LOGD("Writing %d nv_data byte(s) at offset 0x%x failed", header->length, header->offset); - RIL_LOGD("Write rfs_data dump:"); - hex_dump(rfs_data, rfs_io->length > 0x100 ? 0x100 : rfs_io->length); + data.confirm = 0; + } else { + RIL_LOGD("Wrote %d nv_data byte(s) at offset 0x%x", header->length, header->offset); - RIL_LOGD("Asked to write 0x%x bytes at offset 0x%x", rfs_io->length, rfs_io->offset); - rc = nv_data_write(ipc_client, rfs_io->offset, rfs_io->length, rfs_data); + data.confirm = 1; + data.offset = header->offset; + data.length = header->length; + } - RIL_LOGD("Sending RFS IO Confirm message (rc is %d)", rc); - rfs_io_conf.confirm = rc < 0 ? 0 : 1; - rfs_io_conf.offset = rfs_io->offset; - rfs_io_conf.length = rfs_io->length; + rc = ipc_rfs_send(message->aseq, IPC_RFS_NV_WRITE_ITEM, (void *) &data, sizeof(data)); + if (rc < 0) + return 0; - ipc_rfs_send(IPC_RFS_NV_WRITE_ITEM, (unsigned char *) &rfs_io_conf, sizeof(struct ipc_rfs_io_confirm), info->aseq); + return 0; } diff --git a/samsung-ril.c b/samsung-ril.c index 245685e..43784a7 100644 --- a/samsung-ril.c +++ b/samsung-ril.c @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,805 +18,1501 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdlib.h> +#include <ctype.h> + #define LOG_TAG "RIL" -#include "samsung-ril.h" -#include "util.h" +#include <utils/Log.h> +#include <telephony/ril.h> + +#include <samsung-ril.h> +#include <utils.h> /* * RIL data */ -struct ril_data ril_data; +struct ril_data *ril_data = NULL; /* - * RIL requests + * RIL clients */ -int ril_request_id_get(void) -{ - ril_data.request_id++; - ril_data.request_id %= 0xff; +struct ril_client *ril_clients[] = { + &ipc_fmt_client, + &ipc_rfs_client, + &srs_client, +}; - return ril_data.request_id; -} +unsigned int ril_clients_count = sizeof(ril_clients) / + sizeof(struct ril_client *); + +struct ipc_dispatch_handler ipc_fmt_dispatch_handlers[] = { + /* Power */ + { + .command = IPC_PWR_PHONE_PWR_UP, + .handler = ipc_pwr_phone_pwr_up, + }, + { + .command = IPC_PWR_PHONE_RESET, + .handler = ipc_pwr_phone_reset, + }, + { + .command = IPC_PWR_PHONE_STATE, + .handler = ipc_pwr_phone_state, + }, + /* Call */ + { + .command = IPC_CALL_INCOMING, + .handler = ipc_call_incoming, + }, + { + .command = IPC_CALL_STATUS, + .handler = ipc_call_status, + }, + { + .command = IPC_CALL_LIST, + .handler = ipc_call_list, + }, + { + .command = IPC_CALL_BURST_DTMF, + .handler = ipc_call_burst_dtmf, + }, + /* SMS */ + { + .command = IPC_SMS_SEND_MSG, + .handler = ipc_sms_send_msg, + }, + { + .command = IPC_SMS_INCOMING_MSG, + .handler = ipc_sms_incoming_msg, + }, + { + .command = IPC_SMS_SAVE_MSG, + .handler = ipc_sms_save_msg, + }, + { + .command = IPC_SMS_DEL_MSG, + .handler = ipc_sms_del_msg, + }, + { + .command = IPC_SMS_DELIVER_REPORT, + .handler = ipc_sms_deliver_report, + }, + { + .command = IPC_SMS_SVC_CENTER_ADDR, + .handler = ipc_sms_svc_center_addr, + }, + /* SIM */ + { + .command = IPC_SEC_PIN_STATUS, + .handler = ipc_sec_pin_status, + }, + { + .command = IPC_SEC_PHONE_LOCK, + .handler = ipc_sec_phone_lock, + }, + { + .command = IPC_SEC_RSIM_ACCESS, + .handler = ipc_sec_rsim_access, + }, + { + .command = IPC_SEC_SIM_ICC_TYPE, + .handler = ipc_sec_sim_icc_type, + }, + { + .command = IPC_SEC_LOCK_INFOMATION, + .handler = ipc_sec_lock_infomation, + }, + /* Network */ + { + .command = IPC_DISP_ICON_INFO, + .handler = ipc_disp_icon_info, + }, + { + .command = IPC_DISP_RSSI_INFO, + .handler = ipc_disp_rssi_info, + }, + { + .command = IPC_NET_PLMN_SEL, + .handler = ipc_net_plmn_sel, + }, + { + .command = IPC_NET_SERVING_NETWORK, + .handler = ipc_net_serving_network, + }, + { + .command = IPC_NET_PLMN_LIST, + .handler = ipc_net_plmn_list, + }, + { + .command = IPC_NET_REGIST, + .handler = ipc_net_regist, + }, + { + .command = IPC_NET_MODE_SEL, + .handler = ipc_net_mode_sel, + }, + /* Misc */ + { + .command = IPC_MISC_ME_VERSION, + .handler = ipc_misc_me_version, + }, + { + .command = IPC_MISC_ME_IMSI, + .handler = ipc_misc_me_imsi, + }, + { + .command = IPC_MISC_ME_SN, + .handler = ipc_misc_me_sn, + }, + { + .command = IPC_MISC_TIME_INFO, + .handler = ipc_misc_time_info, + }, + /* OEM */ + { + .command = IPC_SVC_DISPLAY_SCREEN, + .handler = ipc_svc_display_screen, + }, + /* Data */ + { + .command = IPC_GPRS_PS, + .handler = ipc_gprs_ps, + }, + { + .command = IPC_GPRS_PDP_CONTEXT, + .handler = ipc_gprs_pdp_context, + }, + { + .command = IPC_GPRS_IP_CONFIGURATION, + .handler = ipc_gprs_ip_configuration, + }, + { + .command = IPC_GPRS_HSDPA_STATUS, + .handler = ipc_gprs_hsdpa_status, + }, + { + .command = IPC_GPRS_CALL_STATUS, + .handler = ipc_gprs_call_status, + }, + /* GEN */ + { + .command = IPC_GEN_PHONE_RES, + .handler = ipc_gen_phone_res, + }, +}; + +unsigned int ipc_fmt_dispatch_handlers_count = sizeof(ipc_fmt_dispatch_handlers) / + sizeof(struct ipc_dispatch_handler); + +struct ipc_dispatch_handler ipc_rfs_dispatch_handlers[] = { + { + .command = IPC_RFS_NV_READ_ITEM, + .handler = ipc_rfs_nv_read_item, + }, + { + .command = IPC_RFS_NV_WRITE_ITEM, + .handler = ipc_rfs_nv_write_item, + }, +}; + +unsigned int ipc_rfs_dispatch_handlers_count = sizeof(ipc_rfs_dispatch_handlers) / + sizeof(struct ipc_dispatch_handler); + +struct srs_dispatch_handler srs_dispatch_handlers[] = { + { + .command = SRS_CONTROL_PING, + .handler = srs_control_ping, + }, + { + .command = SRS_SND_SET_CALL_VOLUME, + .handler = srs_snd_set_call_volume, + }, + { + .command = SRS_SND_SET_CALL_AUDIO_PATH, + .handler = srs_snd_set_call_audio_path, + }, + { + .command = SRS_SND_SET_CALL_CLOCK_SYNC, + .handler = srs_snd_set_call_clock_sync, + }, +}; + +unsigned int srs_dispatch_handlers_count = sizeof(srs_dispatch_handlers) / + sizeof(struct srs_dispatch_handler); + +/* + * RIL request + */ + +struct ril_request_handler ril_request_handlers[] = { + /* Power */ + { + .request = RIL_REQUEST_RADIO_POWER, + .handler = ril_request_radio_power, + }, + /* Call */ + { + .request = RIL_REQUEST_DIAL, + .handler = ril_request_dial, + }, + { + .request = RIL_REQUEST_HANGUP, + .handler = ril_request_hangup, + }, + { + .request = RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, + .handler = ril_request_hangup, + }, + { + .request = RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, + .handler = ril_request_hangup, + }, + { + .request = RIL_REQUEST_ANSWER, + .handler = ril_request_answer, + }, + { + .request = RIL_REQUEST_LAST_CALL_FAIL_CAUSE, + .handler = ril_request_last_call_fail_cause, + }, + { + .request = RIL_REQUEST_GET_CURRENT_CALLS, + .handler = ril_request_get_current_calls, + }, + { + .request = RIL_REQUEST_DTMF, + .handler = ril_request_dtmf, + }, + { + .request = RIL_REQUEST_DTMF_START, + .handler = ril_request_dtmf_start, + }, + { + .request = RIL_REQUEST_DTMF_STOP, + .handler = ril_request_dtmf_stop, + }, + /* SMS */ + { + .request = RIL_REQUEST_SEND_SMS, + .handler = ril_request_send_sms, + }, + { + .request = RIL_REQUEST_SEND_SMS_EXPECT_MORE, + .handler = ril_request_send_sms, + }, + { + .request = RIL_REQUEST_WRITE_SMS_TO_SIM, + .handler = ril_request_write_sms_to_sim, + }, + { + .request = RIL_REQUEST_DELETE_SMS_ON_SIM, + .handler = ril_request_delete_sms_on_sim, + }, + { + .request = RIL_REQUEST_SMS_ACKNOWLEDGE, + .handler = ril_request_sms_acknowledge, + }, + /* 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_SET_FACILITY_LOCK, + .handler = ril_request_set_facility_lock, + }, + { + .request = RIL_REQUEST_ENTER_SIM_PIN, + .handler = ril_request_enter_sim_pin, + }, + { + .request = RIL_REQUEST_ENTER_SIM_PUK, + .handler = ril_request_enter_sim_puk, + }, + { + .request = RIL_REQUEST_ENTER_SIM_PIN2, + .handler = ril_request_enter_sim_pin2, + }, + { + .request = RIL_REQUEST_ENTER_SIM_PUK2, + .handler = ril_request_enter_sim_puk2, + }, + { + .request = RIL_REQUEST_CHANGE_SIM_PIN, + .handler = ril_request_change_sim_pin, + }, + { + .request = RIL_REQUEST_CHANGE_SIM_PIN2, + .handler = ril_request_change_sim_pin2, + }, + { + .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_SET_NETWORK_SELECTION_AUTOMATIC, + .handler = ril_request_set_network_selection_automatic, + }, + { + .request = RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, + .handler = ril_request_set_network_selection_manual, + }, + { + .request = RIL_REQUEST_OPERATOR, + .handler = ril_request_operator, + }, + { + .request = RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, + .handler = ril_request_query_available_networks, + }, + { +#if RIL_VERSION >= 6 + .request = RIL_REQUEST_VOICE_REGISTRATION_STATE, + .handler = ril_request_voice_registration_state, +#else + .request = RIL_REQUEST_REGISTRATION_STATE, + .handler = ril_request_registration_state, +#endif + }, + { +#if RIL_VERSION >= 6 + .request = RIL_REQUEST_DATA_REGISTRATION_STATE, + .handler = ril_request_data_registration_state, +#else + .request = RIL_REQUEST_GPRS_REGISTRATION_STATE, + .handler = ril_request_gprs_registration_state, +#endif + }, + { + .request = RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, + .handler = ril_request_get_preferred_network_type, + }, + { + .request = RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, + .handler = ril_request_set_preferred_network_type, + }, + /* Sound */ + { + .request = RIL_REQUEST_SET_MUTE, + .handler = ril_request_set_mute, + }, + /* 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, + }, + /* OEM */ + { + .request = RIL_REQUEST_OEM_HOOK_RAW, + .handler = ril_request_oem_hook_raw, + }, + /* Data */ + { + .request = RIL_REQUEST_SETUP_DATA_CALL, + .handler = ril_request_setup_data_call, + }, + { + .request = RIL_REQUEST_DEACTIVATE_DATA_CALL, + .handler = ril_request_deactivate_data_call, + }, + { + .request = RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, + .handler = ril_request_last_data_call_fail_cause, + }, + { + .request = RIL_REQUEST_DATA_CALL_LIST, + .handler = ril_request_data_call_list, + }, +}; -int ril_request_id_set(int id) +unsigned int ril_request_handlers_count = sizeof(ril_request_handlers) / + sizeof(struct ril_request_handler); + +int ril_request_stats_log(void) { - id %= 0xff; + 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; - while (ril_data.request_id < id) { - ril_data.request_id++; - ril_data.request_id %= 0xff; + list = ril_data->requests_data; + while (list != NULL) { + count++; + + list = list->next; } - return ril_data.request_id; + 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(RIL_Token t, int id) +int ril_request_register(int request, void *data, size_t size, RIL_Token token) { - struct ril_request_info *request; + struct ril_request *ril_request; struct list_head *list_end; struct list_head *list; + unsigned int i; - request = calloc(1, sizeof(struct ril_request_info)); - if (request == NULL) + if (ril_data == NULL) return -1; - request->token = t; - request->id = id; - request->canceled = 0; + 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; - list_end = ril_data.requests; + 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((void *) request, list_end, NULL); + list = list_head_alloc(list_end, NULL, (void *) ril_request); + + if (ril_data->requests == NULL) + ril_data->requests = list; + + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; - if (ril_data.requests == NULL) - ril_data.requests = list; + ril_client_request_register(ril_clients[i], request, token); + } + + RIL_REQUEST_UNLOCK(); return 0; } -void ril_request_unregister(struct ril_request_info *request) +int ril_request_unregister(struct ril_request *request) { struct list_head *list; + unsigned int i; - if (request == NULL) - return; + if (request == NULL || ril_data == NULL) + return -1; + + RIL_REQUEST_LOCK(); + + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; + + ril_client_request_unregister(ril_clients[i], request->request, request->token); + } - list = ril_data.requests; + list = ril_data->requests; while (list != NULL) { if (list->data == (void *) request) { - memset(request, 0, sizeof(struct ril_request_info)); + 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; + 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; } -struct ril_request_info *ril_request_info_find_id(int id) +int ril_request_flush(void) { - struct ril_request_info *request; + 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; + list = ril_data->requests; while (list != NULL) { - request = (struct ril_request_info *) list->data; - if (request == 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; - if (request->id == id) - return request; + request = (struct ril_request *) list->data; + + RIL_REQUEST_UNLOCK(); + return request; list_continue: list = list->next; } + RIL_REQUEST_UNLOCK(); + return NULL; } -struct ril_request_info *ril_request_info_find_token(RIL_Token t) +struct ril_request *ril_request_find_request_status(int request, int status) { - struct ril_request_info *request; + struct ril_request *ril_request; struct list_head *list; - list = ril_data.requests; + if (ril_data == NULL) + return NULL; + + RIL_REQUEST_LOCK(); + + list = ril_data->requests; while (list != NULL) { - request = (struct ril_request_info *) list->data; - if (request == NULL) + if (list->data == NULL) goto list_continue; - if (request->token == t) - return request; + 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; } -int ril_request_set_canceled(RIL_Token t, int canceled) +struct ril_request *ril_request_find_request(int request) { - struct ril_request_info *request; + struct ril_request *ril_request; + struct list_head *list; - request = ril_request_info_find_token(t); - if (request == NULL) - return -1; + if (ril_data == NULL) + return NULL; - request->canceled = canceled ? 1 : 0; + RIL_REQUEST_LOCK(); - return 0; -} + list = ril_data->requests; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; -int ril_request_get_canceled(RIL_Token t) -{ - struct ril_request_info *request; + ril_request = (struct ril_request *) list->data; - request = ril_request_info_find_token(t); - if (request == NULL) - return -1; + if (ril_request->request == request) { + RIL_REQUEST_UNLOCK(); + return ril_request; + } + +list_continue: + list = list->next; + } + + RIL_REQUEST_UNLOCK(); - return request->canceled; + return NULL; } -RIL_Token ril_request_get_token(int id) +struct ril_request *ril_request_find_token(RIL_Token token) { - struct ril_request_info *request; + struct ril_request *request; + struct list_head *list; - request = ril_request_info_find_id(id); - if (request == NULL) - return RIL_TOKEN_NULL; + 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; + } - return request->token; + RIL_REQUEST_UNLOCK(); + + return NULL; } -int ril_request_get_id(RIL_Token t) +struct ril_request *ril_request_find_status(int status) { - struct ril_request_info *request; - int id, rc; + struct ril_request *request; + struct list_head *list; - request = ril_request_info_find_token(t); - if (request != NULL) - return request->id; + if (ril_data == NULL) + return NULL; - id = ril_request_id_get(); + RIL_REQUEST_LOCK(); - // Unregister a previous request with the same id - request = ril_request_info_find_id(id); - if (request != NULL) - ril_request_unregister(request); + list = ril_data->requests; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; - rc = ril_request_register(t, id); - if (rc < 0) - return -1; + request = (struct ril_request *) list->data; + + if (request->status == status) { + RIL_REQUEST_UNLOCK(); + return request; + } - return id; +list_continue: + list = list->next; + } + + RIL_REQUEST_UNLOCK(); + + return NULL; } -void ril_request_complete(RIL_Token t, RIL_Errno e, void *data, size_t length) +int ril_request_complete(RIL_Token token, RIL_Errno error, void *data, + size_t size) { - struct ril_request_info *request; - int canceled = 0; + struct ril_request *request; + + if (ril_data == NULL || ril_data->env == NULL || ril_data->env->OnRequestComplete == NULL) + return -1; - request = ril_request_info_find_token(t); + if (token == NULL) + return 0; + + request = ril_request_find_token(token); if (request == NULL) goto complete; - canceled = ril_request_get_canceled(t); ril_request_unregister(request); - if (canceled) - return; + ril_request_stats_log(); complete: - ril_data.env->OnRequestComplete(t, e, data, length); + ril_data->env->OnRequestComplete(token, error, data, size); + + RIL_REQUEST_LOOP_UNLOCK(); + + return 0; } -void ril_request_unsolicited(int request, void *data, size_t length) +int ril_request_unsolicited(int request, void *data, size_t size) { - ril_data.env->OnUnsolicitedResponse(request, data, length); + if (ril_data == NULL || ril_data->env == NULL || ril_data->env->OnUnsolicitedResponse == NULL) + return -1; + + ril_data->env->OnUnsolicitedResponse(request, data, size); + + return 0; } -void ril_request_timed_callback(RIL_TimedCallback callback, void *data, const struct timeval *time) +int ril_request_timed_callback(RIL_TimedCallback callback, void *data, + const struct timeval *time) { - ril_data.env->RequestTimedCallback(callback, data, time); -} + if (ril_data == NULL || ril_data->env == NULL || ril_data->env->RequestTimedCallback == NULL) + return -1; -/* - * RIL radio state - */ + ril_data->env->RequestTimedCallback(callback, data, time); -int ril_radio_state_complete(RIL_RadioState radio_state, RIL_Token token) -{ - RIL_Errno error = RIL_E_SUCCESS; + return 0; +} - // This goes from best case of failure to worst case of failure - switch (radio_state) { - case RADIO_STATE_SIM_NOT_READY: - if (ril_data.state.radio_state == RADIO_STATE_SIM_NOT_READY) - error = RIL_E_GENERIC_FAILURE; - case RADIO_STATE_SIM_LOCKED_OR_ABSENT: - if (ril_data.state.radio_state == RADIO_STATE_SIM_LOCKED_OR_ABSENT) - error = RIL_E_GENERIC_FAILURE; - case RADIO_STATE_OFF: - if (ril_data.state.radio_state == RADIO_STATE_OFF) - error = RIL_E_RADIO_NOT_AVAILABLE; - case RADIO_STATE_UNAVAILABLE: - default: - if (ril_data.state.radio_state == RADIO_STATE_UNAVAILABLE) - error = RIL_E_RADIO_NOT_AVAILABLE; - break; - } +int ril_request_dispatch(struct ril_request *request) +{ + unsigned int i; + int status; + int rc; - if (error != RIL_E_SUCCESS) { - if (token != RIL_TOKEN_NULL) - ril_request_complete(token, error, NULL, 0); + if (request == NULL || ril_data == NULL) + return -1; - 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; } -void ril_radio_state_update(RIL_RadioState radio_state) +void *ril_request_loop(void *data) { - RIL_LOGD("Setting radio state to %d", radio_state); - ril_data.state.radio_state = radio_state; + struct ril_request *request; + int rc; - ril_request_unsolicited(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); + if (ril_data == NULL) + return NULL; + + while (1) { + RIL_REQUEST_LOOP_LOCK(); + + RIL_LOCK(); + + rc = ril_radio_state_check(RADIO_STATE_OFF); + if (rc < 0) { + RIL_UNLOCK(); + continue; + } - ril_tokens_check(); + 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); + + RIL_UNLOCK(); + } + + return NULL; } /* - * RIL tokens + * RIL request data */ -void ril_tokens_check(void) +int ril_request_data_register(int request, void *data, size_t size) { - RIL_Token t; + 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; - if (ril_data.tokens.baseband_version != 0) { - if (ril_data.state.radio_state != RADIO_STATE_OFF) { - t = ril_data.tokens.baseband_version; - ril_data.tokens.baseband_version = 0; - ril_request_baseband_version(t); + 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; } - if (ril_data.tokens.get_imei != 0 && ril_data.tokens.get_imeisv != 0) { - if (ril_data.state.radio_state != RADIO_STATE_OFF) { - t = ril_data.tokens.get_imei; - ril_data.tokens.get_imei = 0; - ril_request_get_imei(t); + 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; } /* - * Clients dispatch functions + * RIL radio state */ -void ipc_fmt_dispatch(struct ipc_message_info *info) +int ril_radio_state_update(RIL_RadioState radio_state) { - if (info == NULL) - return; + struct ril_request *request; + unsigned int i; + int rc; - RIL_LOCK(); + if (ril_data == NULL) + return -1; - ril_request_id_set(info->aseq); + if (ril_data->radio_state == radio_state) + return 0; - switch (IPC_COMMAND(info)) { - /* GEN */ - case IPC_GEN_PHONE_RES: - ipc_gen_phone_res(info); - break; - /* PWR */ - case IPC_PWR_PHONE_PWR_UP: - ipc_pwr_phone_pwr_up(); - break; - case IPC_PWR_PHONE_RESET: - ipc_pwr_phone_reset(); - break; - case IPC_PWR_PHONE_STATE: - ipc_pwr_phone_state(info); - break; - /* DISP */ - case IPC_DISP_ICON_INFO: - ipc_disp_icon_info(info); - break; - case IPC_DISP_RSSI_INFO: - ipc_disp_rssi_info(info); - break; - /* MISC */ - case IPC_MISC_ME_SN: - ipc_misc_me_sn(info); - break; - case IPC_MISC_ME_VERSION: - ipc_misc_me_version(info); - break; - case IPC_MISC_ME_IMSI: - ipc_misc_me_imsi(info); - break; - case IPC_MISC_TIME_INFO: - ipc_misc_time_info(info); - break; - /* SAT */ -#ifndef DISABLE_STK - case IPC_SAT_PROACTIVE_CMD: - ipc_sat_proactive_cmd(info); - break; - case IPC_SAT_ENVELOPE_CMD: - ipc_sat_envelope_cmd(info); - break; -#endif - /* SS */ - case IPC_SS_USSD: - ipc_ss_ussd(info); - break; - /* SEC */ - case IPC_SEC_SIM_STATUS: - ipc_sec_sim_status(info); - break; - case IPC_SEC_SIM_ICC_TYPE: - ipc_sec_sim_icc_type(info); - break; - case IPC_SEC_LOCK_INFO: - ipc_sec_lock_info(info); - break; - case IPC_SEC_RSIM_ACCESS: - ipc_sec_rsim_access(info); - break; - case IPC_SEC_PHONE_LOCK: - ipc_sec_phone_lock(info); - break; - /* NET */ - case IPC_NET_CURRENT_PLMN: - ipc_net_current_plmn(info); - break; - case IPC_NET_REGIST: - ipc_net_regist(info); - break; - case IPC_NET_PLMN_LIST: - ipc_net_plmn_list(info); - break; - case IPC_NET_PLMN_SEL: - ipc_net_plmn_sel(info); - break; - case IPC_NET_MODE_SEL: - ipc_net_mode_sel(info); - break; - /* SMS */ - case IPC_SMS_INCOMING_MSG: - ipc_sms_incoming_msg(info); - break; - case IPC_SMS_DELIVER_REPORT: - ipc_sms_deliver_report(info); - break; - case IPC_SMS_SVC_CENTER_ADDR: - ipc_sms_svc_center_addr(info); - break; - case IPC_SMS_SEND_MSG: - ipc_sms_send_msg(info); - break; - case IPC_SMS_DEVICE_READY: - ipc_sms_device_ready(info); - break; - case IPC_SMS_SAVE_MSG: - ipc_sms_save_msg(info); - break; - case IPC_SMS_DEL_MSG: - ipc_sms_del_msg(info); - break; - /* SVC */ - case IPC_SVC_DISPLAY_SCREEN: - ipc_svc_display_screen(info); - break; - /* CALL */ - case IPC_CALL_INCOMING: - ipc_call_incoming(info); - break; - case IPC_CALL_LIST: - ipc_call_list(info); - break; - case IPC_CALL_STATUS: - ipc_call_status(info); - break; - case IPC_CALL_BURST_DTMF: - ipc_call_burst_dtmf(info); - break; - /* GPRS */ - case IPC_GPRS_IP_CONFIGURATION: - ipc_gprs_ip_configuration(info); - break; - case IPC_GPRS_CALL_STATUS: - ipc_gprs_call_status(info); - break; - case IPC_GPRS_PDP_CONTEXT: - ipc_gprs_pdp_context(info); + 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(); + + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; + + ril_client_flush(ril_clients[i]); + } + case RADIO_STATE_OFF: + ril_data_connection_flush(); + + 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: - RIL_LOGE("%s: Unhandled request: %s (%04x)", __func__, ipc_command_to_str(IPC_COMMAND(info)), IPC_COMMAND(info)); + RIL_REQUEST_LOOP_UNLOCK(); break; } - RIL_UNLOCK(); + return 0; } -void ipc_rfs_dispatch(struct ipc_message_info *info) +int ril_radio_state_check(RIL_RadioState radio_state) { - if (info == NULL) - return; + 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; - RIL_LOCK(); + count = sizeof(radio_states) / sizeof(RIL_RadioState); - switch (IPC_COMMAND(info)) { - case IPC_RFS_NV_READ_ITEM: - ipc_rfs_nv_read_item(info); - break; - case IPC_RFS_NV_WRITE_ITEM: - ipc_rfs_nv_write_item(info); + for (i = 0; i < count; i++) + if (radio_states[i] == radio_state) break; - default: - RIL_LOGE("%s: Unhandled request: %s (%04x)", __func__, ipc_command_to_str(IPC_COMMAND(info)), IPC_COMMAND(info)); + + index = i; + + for (i = 0; i < count; i++) + if (radio_states[i] == ril_data->radio_state) break; - } - RIL_UNLOCK(); + if (i < index) + return -1; + + return 0; } -void srs_dispatch(struct srs_message *message) +/* + * RIL data + */ + +int ril_data_create(void) { - if (message == NULL) - return; + ril_data = (struct ril_data *) calloc(1, sizeof(struct ril_data)); - RIL_LOCK(); + pthread_mutex_init(&ril_data->mutex, NULL); + pthread_mutex_init(&ril_data->request_mutex, NULL); + pthread_mutex_init(&ril_data->request_loop_mutex, NULL); - switch (message->command) { - case SRS_CONTROL_PING: - srs_control_ping(message); - break; - case SRS_SND_SET_CALL_CLOCK_SYNC: - srs_snd_set_call_clock_sync(message); - break; - case SRS_SND_SET_CALL_VOLUME: - srs_snd_set_call_volume(message); - break; - case SRS_SND_SET_CALL_AUDIO_PATH: - srs_snd_set_call_audio_path(message); - break; - default: - RIL_LOGE("%s: Unhandled request: (%04x)", __func__, message->command); - break; - } + RIL_REQUEST_LOOP_LOCK(); - RIL_UNLOCK(); + ril_data->radio_state = RADIO_STATE_UNAVAILABLE; + + return 0; +} + +int ril_data_destroy(void) +{ + if (ril_data == NULL) + return -1; + + pthread_mutex_destroy(&ril_data->mutex); + pthread_mutex_destroy(&ril_data->request_mutex); + pthread_mutex_destroy(&ril_data->request_loop_mutex); + + free(ril_data); + ril_data = NULL; + + return 0; } /* * RIL interface */ -void ril_on_request(int request, void *data, size_t length, RIL_Token t) +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_LOCK(); + ril_request = ril_request_find_token(token); + if (ril_request != NULL) + ril_request_unregister(ril_request); + switch (request) { - /* PWR */ - case RIL_REQUEST_RADIO_POWER: - ril_request_radio_power(t, data, length); - break; - case RIL_REQUEST_BASEBAND_VERSION: - ril_request_baseband_version(t); - break; - /* DISP */ - case RIL_REQUEST_SIGNAL_STRENGTH: - ril_request_signal_strength(t); - break; - /* MISC */ - case RIL_REQUEST_GET_IMEI: - ril_request_get_imei(t); - break; - case RIL_REQUEST_GET_IMEISV: - ril_request_get_imeisv(t); - break; - case RIL_REQUEST_GET_IMSI: - ril_request_get_imsi(t); - break; - /* SAT */ -#ifndef DISABLE_STK - case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: - ril_request_report_stk_service_is_running(t); - break; - case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: - ril_request_stk_send_terminal_response(t, data, length); - break; - case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: - ril_request_stk_send_envelope_command(t, data, length); - break; - case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: - ril_request_complete(t, RIL_E_SUCCESS, NULL, 0); - break; -#endif - /* SS */ - case RIL_REQUEST_SEND_USSD: - ril_request_send_ussd(t, data, length); - break; - case RIL_REQUEST_CANCEL_USSD: - ril_request_cancel_ussd(t, data, length); - break; - /* SEC */ - case RIL_REQUEST_GET_SIM_STATUS: - ril_request_get_sim_status(t); - break; - case RIL_REQUEST_SIM_IO: - ril_request_sim_io(t, data, length); - break; - case RIL_REQUEST_ENTER_SIM_PIN: - ril_request_enter_sim_pin(t, data, length); - break; - case RIL_REQUEST_CHANGE_SIM_PIN: - ril_request_change_sim_pin(t, data, length); + 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_ENTER_SIM_PUK: - ril_request_enter_sim_puk(t, data, length); + 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: - ril_request_query_facility_lock(t, data, length); - break; case RIL_REQUEST_SET_FACILITY_LOCK: - ril_request_set_facility_lock(t, data, length); - break; - /* SVC */ - case RIL_REQUEST_OEM_HOOK_RAW: - ril_request_oem_hook_raw(t, data, length); - break; - /* NET */ - case RIL_REQUEST_OPERATOR: - ril_request_operator(t); + 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 RIL_VERSION >= 6 - case RIL_REQUEST_VOICE_REGISTRATION_STATE: - ril_request_voice_registration_state(t); - break; - case RIL_REQUEST_DATA_REGISTRATION_STATE: - ril_request_data_registration_state(t); - break; + if (data == NULL || size < sizeof(RIL_SIM_IO_v6)) #else - case RIL_REQUEST_REGISTRATION_STATE: - ril_request_registration_state(t); - break; - case RIL_REQUEST_GPRS_REGISTRATION_STATE: - ril_request_gprs_registration_state(t); - break; + if (data == NULL || size < sizeof(RIL_SIM_IO)) #endif - case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: - ril_request_query_available_networks(t); - break; - case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: - ril_request_get_preferred_network_type(t); - break; - case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: - ril_request_set_preferred_network_type(t, data, length); - break; - case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: - ril_request_query_network_selection_mode(t); - break; - case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: - ril_request_set_network_selection_automatic(t); - break; - case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: - ril_request_set_network_selection_manual(t, data, length); - break; - /* SMS */ - case RIL_REQUEST_SEND_SMS: - ril_request_send_sms(t, data, length); - break; - case RIL_REQUEST_SEND_SMS_EXPECT_MORE: - ril_request_send_sms_expect_more(t, data, length); - break; - case RIL_REQUEST_SMS_ACKNOWLEDGE: - ril_request_sms_acknowledge(t, data, length); - break; - case RIL_REQUEST_WRITE_SMS_TO_SIM: - ril_request_write_sms_to_sim(t, data, length); - break; - case RIL_REQUEST_DELETE_SMS_ON_SIM: - ril_request_delete_sms_on_sim(t, data, length); - break; - /* CALL */ - case RIL_REQUEST_DIAL: - ril_request_dial(t, data, length); - break; - case RIL_REQUEST_GET_CURRENT_CALLS: - ril_request_get_current_calls(t); - break; - case RIL_REQUEST_HANGUP: - case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: - case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: - ril_request_hangup(t); - break; - case RIL_REQUEST_ANSWER: - ril_request_answer(t); - break; - case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: - ril_request_last_call_fail_cause(t); - break; - case RIL_REQUEST_DTMF: - ril_request_dtmf(t, data, length); - break; - case RIL_REQUEST_DTMF_START: - ril_request_dtmf_start(t, data, length); - break; - case RIL_REQUEST_DTMF_STOP: - ril_request_dtmf_stop(t); + break; + + buffer = calloc(1, size); + + memcpy(buffer, data, size); + +#if RIL_VERSION >= 6 + 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); +#else + if (((RIL_SIM_IO *) data)->path != NULL) + ((RIL_SIM_IO *) buffer)->path = strdup(((RIL_SIM_IO *) data)->path); + + if (((RIL_SIM_IO *) data)->data != NULL) + ((RIL_SIM_IO *) buffer)->data = strdup(((RIL_SIM_IO *) data)->data); + + if (((RIL_SIM_IO *) data)->pin2 != NULL) + ((RIL_SIM_IO *) buffer)->pin2 = strdup(((RIL_SIM_IO *) data)->pin2); +#endif + + data = buffer; break; - /* GPRS */ case RIL_REQUEST_SETUP_DATA_CALL: - ril_request_setup_data_call(t, data, length); - break; case RIL_REQUEST_DEACTIVATE_DATA_CALL: - ril_request_deactivate_data_call(t, data, length); - break; - case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: - ril_request_last_data_call_fail_cause(t); - break; - case RIL_REQUEST_DATA_CALL_LIST: - ril_request_data_call_list(t); - break; - /* SND */ - case RIL_REQUEST_SET_MUTE: - ril_request_set_mute(t, data, length); - break; - /* OTHER */ - case RIL_REQUEST_SCREEN_STATE: - /* This doesn't affect anything */ - ril_request_complete(t, RIL_E_SUCCESS, NULL, 0); + strings_count = size / sizeof(char *); break; default: - RIL_LOGE("%s: Unhandled request: %d", __func__, request); - ril_request_complete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); + 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_UNLOCK(); + + RIL_REQUEST_LOOP_UNLOCK(); } + RIL_RadioState ril_on_state_request(void) { - return ril_data.state.radio_state; -} + if (ril_data == NULL) + return RADIO_STATE_UNAVAILABLE; -int ril_on_supports(int request) -{ - return 1; + return ril_data->radio_state; } -void ril_on_cancel(RIL_Token t) +int ril_supports(int request) { - ril_request_set_canceled(t, 1); + 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; } -const char *ril_get_version(void) +void ril_on_cancel(RIL_Token token) { - return RIL_VERSION_STRING; -} + struct ril_request *request; -/* - * RIL init - */ + RIL_LOCK(); -void ril_data_init(void) -{ - memset(&ril_data, 0, sizeof(ril_data)); + request = ril_request_find_token(token); + if (request == NULL) { + RIL_UNLOCK(); + return; + } - pthread_mutex_init(&ril_data.mutex, NULL); + ril_request_unregister(request); - ril_data.state.radio_state = RADIO_STATE_UNAVAILABLE; + ril_request_stats_log(); + + RIL_UNLOCK(); } -/* - * RIL interface - */ +const char *ril_get_version(void) +{ + return RIL_VERSION_STRING; +} -static const RIL_RadioFunctions ril_ops = { - RIL_VERSION >= 6 ? 6 : RIL_VERSION, +RIL_RadioFunctions ril_radio_functions = { + RIL_VERSION, ril_on_request, ril_on_state_request, - ril_on_supports, + ril_supports, ril_on_cancel, ril_get_version }; -const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv) +const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, + char **argv) { - struct ril_client *ipc_fmt_client; - struct ril_client *ipc_rfs_client; - struct ril_client *srs_client; + RIL_RadioFunctions *radio_functions; + pthread_attr_t attr; + unsigned int i; int rc; if (env == NULL) return NULL; - ril_data_init(); - ril_data.env = (struct RIL_Env *) env; - - RIL_LOCK(); - - RIL_LOGD("Creating IPC FMT client"); - - ipc_fmt_client = ril_client_new(&ipc_fmt_client_funcs); - rc = ril_client_create(ipc_fmt_client); - + rc = ril_data_create(); if (rc < 0) { - RIL_LOGE("IPC FMT client creation failed."); - goto ipc_rfs; - } - - rc = ril_client_thread_start(ipc_fmt_client); - - if (rc < 0) { - RIL_LOGE("IPC FMT thread creation failed."); - goto ipc_rfs; + RIL_LOGE("Creating RIL data failed"); + return NULL; } - ril_data.ipc_fmt_client = ipc_fmt_client; - RIL_LOGD("IPC FMT client ready"); - -ipc_rfs: - RIL_LOGD("Creating IPC RFS client"); - - ipc_rfs_client = ril_client_new(&ipc_rfs_client_funcs); - rc = ril_client_create(ipc_rfs_client); + RIL_LOCK(); - if (rc < 0) { - RIL_LOGE("IPC RFS client creation failed."); - goto srs; - } + ril_data->env = env; - rc = ril_client_thread_start(ipc_rfs_client); + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; - if (rc < 0) { - RIL_LOGE("IPC RFS thread creation failed."); - goto srs; + rc = ril_client_create(ril_clients[i]); + if (rc < 0) + goto error; } - ril_data.ipc_rfs_client = ipc_rfs_client; - RIL_LOGD("IPC RFS client ready"); - -srs: - RIL_LOGD("Creating SRS client"); + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; - srs_client = ril_client_new(&srs_client_funcs); - rc = ril_client_create(srs_client); + rc = ril_client_open(ril_clients[i]); + if (rc < 0) + goto error; - if (rc < 0) { - RIL_LOGE("SRS client creation failed."); - goto end; + rc = ril_client_loop(ril_clients[i]); + if (rc < 0) + goto error; } - rc = ril_client_thread_start(srs_client); + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (rc < 0) { - RIL_LOGE("SRS thread creation failed."); - goto end; + rc = pthread_create(&ril_data->request_thread, &attr, ril_request_loop, NULL); + if (rc != 0) { + RIL_LOGE("Starting request loop failed"); + goto error; } - ril_data.srs_client = srs_client; - RIL_LOGD("SRS client ready"); + radio_functions = &ril_radio_functions; + goto complete; -end: +error: + radio_functions = NULL; + +complete: RIL_UNLOCK(); - return &ril_ops; + return radio_functions; } diff --git a/samsung-ril.h b/samsung-ril.h index a154218..2879782 100644 --- a/samsung-ril.h +++ b/samsung-ril.h @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,54 +21,58 @@ #ifndef _SAMSUNG_RIL_H_ #define _SAMSUNG_RIL_H_ -#include <errno.h> +#include <stdlib.h> #include <string.h> #include <pthread.h> -#include <utils/Log.h> #include <telephony/ril.h> #include <samsung-ipc.h> +#include <samsung-ril-socket.h> -#include "ipc.h" -#include "srs.h" +#include <ipc.h> +#include <srs.h> +#include <utils.h> /* - * Defines + * Values + */ + +#define RIL_VERSION_STRING "Samsung-RIL" + +#define RIL_CLIENT_RETRY_COUNT 5 +#define RIL_CLIENT_RETRY_DELAY 50000 + +/* + * Macros */ #ifdef ALOGI -#define RIL_LOGI ALOGI +#define RIL_LOGI ALOGI #else -#define RIL_LOGI LOGI +#define RIL_LOGI LOGI #endif #ifdef ALOGD -#define RIL_LOGD ALOGD +#define RIL_LOGD ALOGD #else -#define RIL_LOGD LOGD +#define RIL_LOGD LOGD #endif #ifdef ALOGE -#define RIL_LOGE ALOGE +#define RIL_LOGE ALOGE #else -#define RIL_LOGE LOGE +#define RIL_LOGE LOGE #endif -#define RIL_VERSION_STRING "Samsung RIL" - -#define RIL_LOCK() pthread_mutex_lock(&ril_data.mutex) -#define RIL_UNLOCK() pthread_mutex_unlock(&ril_data.mutex) -#define RIL_CLIENT_LOCK(client) pthread_mutex_lock(&(client->mutex)) -#define RIL_CLIENT_UNLOCK(client) pthread_mutex_unlock(&(client->mutex)) - -#define RIL_TOKEN_DATA_WAITING (RIL_Token) 0xff -#define RIL_TOKEN_NULL (RIL_Token) 0x00 - -#define RIL_SMS_TPID 0xff -#define RIL_SMS_NUMBER "0123456789" - -#define RIL_CLIENT_MAX_TRIES 7 +#define RIL_LOCK() pthread_mutex_lock(&ril_data->mutex) +#define RIL_UNLOCK() pthread_mutex_unlock(&ril_data->mutex) +#define RIL_REQUEST_LOCK() pthread_mutex_lock(&ril_data->request_mutex) +#define RIL_REQUEST_UNLOCK() pthread_mutex_unlock(&ril_data->request_mutex) +#define RIL_REQUEST_LOOP_LOCK() pthread_mutex_lock(&ril_data->request_loop_mutex) +#define RIL_REQUEST_LOOP_UNLOCK() pthread_mutex_unlock(&ril_data->request_loop_mutex) +#define RIL_CLIENT_LOCK(client) pthread_mutex_lock(&client->mutex) +#define RIL_CLIENT_UNLOCK(client) pthread_mutex_unlock(&client->mutex) /* * RIL client @@ -76,431 +80,377 @@ struct ril_client; -struct ril_client_funcs { +enum { + RIL_CLIENT_IPC_FMT, + RIL_CLIENT_IPC_RFS, + RIL_CLIENT_SRS, +}; + +struct ril_client_handlers { int (*create)(struct ril_client *client); int (*destroy)(struct ril_client *client); - int (*read_loop)(struct ril_client *client); + int (*open)(struct ril_client *client); + int (*close)(struct ril_client *client); + int (*loop)(struct ril_client *client); }; -typedef enum { - RIL_CLIENT_NULL = 0, - RIL_CLIENT_CREATED = 1, - RIL_CLIENT_READY = 2, - RIL_CLIENT_DESTROYED = 3, - RIL_CLIENT_ERROR = 4, -} ril_client_state; +struct ril_client_callbacks { + int (*request_register)(struct ril_client *client, int request, RIL_Token token); + int (*request_unregister)(struct ril_client *client, int request, RIL_Token token); + int (*flush)(struct ril_client *client); +}; struct ril_client { - struct ril_client_funcs funcs; - ril_client_state state; + int id; + char *name; + int critical; + struct ril_client_handlers *handlers; + struct ril_client_callbacks *callbacks; + int failures; + int available; void *data; pthread_t thread; pthread_mutex_t mutex; }; -struct ril_client *ril_client_new(struct ril_client_funcs *client_funcs); -int ril_client_free(struct ril_client *client); +extern struct ril_client *ril_clients[]; +extern unsigned int ril_clients_count; + +extern struct ipc_dispatch_handler ipc_fmt_dispatch_handlers[]; +extern unsigned int ipc_fmt_dispatch_handlers_count; +extern struct ipc_dispatch_handler ipc_rfs_dispatch_handlers[]; +extern unsigned int ipc_rfs_dispatch_handlers_count; +extern struct srs_dispatch_handler srs_dispatch_handlers[]; +extern unsigned int srs_dispatch_handlers_count; + +struct ril_client *ril_client_find_id(int id); int ril_client_create(struct ril_client *client); int ril_client_destroy(struct ril_client *client); -int ril_client_thread_start(struct ril_client *client); +int ril_client_open(struct ril_client *client); +int ril_client_close(struct ril_client *client); +int ril_client_loop(struct ril_client *client); +int ril_client_request_register(struct ril_client *client, int request, + RIL_Token token); +int ril_client_request_unregister(struct ril_client *client, int request, + RIL_Token token); +int ril_client_flush(struct ril_client *client); /* - * RIL requests + * RIL request */ -struct ril_request_info { +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 id; - int canceled; + + int status; }; -int ril_request_id_get(void); -int ril_request_id_set(int id); -int ril_request_register(RIL_Token t, int id); -void ril_request_unregister(struct ril_request_info *request); -struct ril_request_info *ril_request_info_find_id(int id); -struct ril_request_info *ril_request_info_find_token(RIL_Token t); -int ril_request_set_canceled(RIL_Token t, int canceled); -int ril_request_get_canceled(RIL_Token t); -RIL_Token ril_request_get_token(int id); -int ril_request_get_id(RIL_Token t); - -void ril_request_complete(RIL_Token t, RIL_Errno e, void *data, size_t length); -void ril_request_unsolicited(int request, void *data, size_t length); -void ril_request_timed_callback(RIL_TimedCallback callback, void *data, const struct timeval *time); +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_complete(RIL_RadioState radio_state, RIL_Token token); -void ril_radio_state_update(RIL_RadioState radio_state); +int ril_radio_state_update(RIL_RadioState radio_state); +int ril_radio_state_check(RIL_RadioState radio_state); /* - * RIL tokens + * RIL data */ -struct ril_tokens { - RIL_Token radio_power; - RIL_Token pin_status; - RIL_Token get_imei; - RIL_Token get_imeisv; - RIL_Token baseband_version; +struct ril_data { + const struct RIL_Env *env; + + RIL_RadioState radio_state; + char *sim_pin; - RIL_Token registration_state; - RIL_Token gprs_registration_state; - RIL_Token operator; + struct list_head *requests; + struct list_head *requests_data; + + struct list_head *data_connections; - RIL_Token outgoing_sms; - RIL_Token sim_io; + pthread_mutex_t mutex; + + pthread_t request_thread; + pthread_mutex_t request_mutex; + pthread_mutex_t request_loop_mutex; }; -void ril_tokens_check(void); +extern struct ril_data *ril_data; + +int ril_data_create(void); +int ril_data_destroy(void); /* - * RIL state + * Power */ -typedef enum { - SIM_STATE_ABSENT = 0, - SIM_STATE_NOT_READY = 1, - SIM_STATE_READY = 2, - SIM_STATE_PIN = 3, - SIM_STATE_PUK = 4, - SIM_STATE_BLOCKED = 5, - SIM_STATE_NETWORK_PERSO = 6, - SIM_STATE_NETWORK_SUBSET_PERSO = 7, - SIM_STATE_CORPORATE_PERSO = 8, - SIM_STATE_SERVICE_PROVIDER_PERSO = 9, -} ril_sim_state; - -struct ril_state { - RIL_RadioState radio_state; - ril_sim_state sim_state; +int ipc_pwr_phone_pwr_up(struct ipc_message *message); +int ipc_pwr_phone_reset(struct ipc_message *message); +int ipc_pwr_phone_state(struct ipc_message *message); +int ril_request_radio_power(void *data, size_t size, RIL_Token token); - struct ipc_sec_sim_status_response sim_pin_status; - struct ipc_sec_sim_icc_type sim_icc_type; +/* + * Call + */ - struct ipc_net_regist_response netinfo; - struct ipc_net_regist_response gprs_netinfo; - struct ipc_net_current_plmn_response plmndata; +int ril_request_dial(void *data, size_t size, RIL_Token token); +int ipc_call_incoming(struct ipc_message *message); +int ril_request_hangup(void *data, size_t size, RIL_Token token); +int ril_request_answer(void *data, size_t size, RIL_Token token); +int ipc_call_status(struct ipc_message *message); +int ril_request_last_call_fail_cause(void *data, size_t size, RIL_Token token); +int ipc_call_list(struct ipc_message *message); +int ril_request_get_current_calls(void *data, size_t size, RIL_Token token); +int ipc_call_cont_dtmf_callback(struct ipc_message *message); +int ipc_call_burst_dtmf(struct ipc_message *message); +int ril_request_dtmf_complete(unsigned char aseq, char tone); +int ril_request_dtmf(void *data, size_t size, RIL_Token token); +int ril_request_dtmf_start_complete(unsigned char aseq, char tone); +int ril_request_dtmf_start(void *data, size_t size, RIL_Token token); +int ril_request_dtmf_stop_complete(unsigned char aseq, int callback); +int ril_request_dtmf_stop(void *data, size_t size, RIL_Token token); - struct ipc_call_status call_status; +/* + * SMS + */ - int gprs_last_failed_cid; +int ipc_sms_send_msg(struct ipc_message *message); +int ril_request_send_sms_complete(unsigned char seq, const void *smsc, + size_t smsc_size, const void *pdu, size_t pdu_size); +int ril_request_send_sms(void *data, size_t size, RIL_Token token); +int ipc_sms_incoming_msg(struct ipc_message *message); +int ipc_sms_save_msg(struct ipc_message *message); +int ril_request_write_sms_to_sim(void *data, size_t size, RIL_Token token); +int ipc_sms_del_msg(struct ipc_message *message); +int ril_request_delete_sms_on_sim(void *data, size_t size, RIL_Token token); +int ipc_sms_deliver_report(struct ipc_message *message); +int ril_request_sms_acknowledge(void *data, size_t size, RIL_Token token); +int ipc_sms_svc_center_addr(struct ipc_message *message); - unsigned char dtmf_tone; - unsigned char ussd_state; +/* + * SIM + */ - unsigned char sms_incoming_msg_tpid; - unsigned char ril_sms_tpid; -}; +int ipc_sec_pin_status_callback(struct ipc_message *message); +int ipc_sec_pin_status(struct ipc_message *message); +int ril_request_get_sim_status(void *data, size_t size, RIL_Token token); +int ipc_sec_phone_lock(struct ipc_message *message); +int ril_request_query_facility_lock(void *data, size_t size, RIL_Token token); +int ipc_sec_callback(struct ipc_message *message); +int ril_request_set_facility_lock(void *data, size_t size, RIL_Token token); +int ril_request_enter_sim_pin(void *data, size_t size, RIL_Token token); +int ril_request_enter_sim_puk(void *data, size_t size, RIL_Token token); +int ril_request_enter_sim_pin2(void *data, size_t size, RIL_Token token); +int ril_request_enter_sim_puk2(void *data, size_t size, RIL_Token token); +int ril_request_change_sim_pin(void *data, size_t size, RIL_Token token); +int ril_request_change_sim_pin2(void *data, size_t size, RIL_Token token); +int ipc_sec_rsim_access(struct ipc_message *message); +int ril_request_sim_io(void *data, size_t size, RIL_Token token); +int ipc_sec_sim_icc_type(struct ipc_message *message); +int ipc_sec_lock_infomation(struct ipc_message *message); /* - * RIL data + * Network */ -struct ril_data { - struct RIL_Env *env; - - struct ril_state state; - struct ril_tokens tokens; - struct ril_oem_hook_svc_session *oem_hook_svc_session; - struct list_head *gprs_connections; - struct list_head *incoming_sms; - struct list_head *outgoing_sms; - struct list_head *sim_io; - struct list_head *generic_responses; - struct list_head *requests; - int request_id; - - struct ril_client *ipc_fmt_client; - struct ril_client *ipc_rfs_client; - struct ril_client *srs_client; +int ipc_disp_icon_info(struct ipc_message *message); +int ril_request_signal_strength(void *data, size_t size, RIL_Token token); +int ipc_disp_rssi_info(struct ipc_message *message); +int ipc_net_plmn_sel(struct ipc_message *message); +int ril_request_query_network_selection_mode(void *data, size_t size, + RIL_Token token); +int ipc_net_plmn_sel_callback(struct ipc_message *message); +int ril_request_set_network_selection_automatic(void *data, size_t size, + RIL_Token token); +int ril_request_set_network_selection_manual(void *data, size_t size, + RIL_Token token); +int ipc_net_serving_network(struct ipc_message *message); +int ril_request_operator(void *data, size_t size, RIL_Token token); +int ipc_net_plmn_list(struct ipc_message *message); +int ril_request_query_available_networks(void *data, size_t size, + RIL_Token token); +int ipc_net_regist(struct ipc_message *message); +#if RIL_VERSION >= 6 +int ril_request_voice_registration_state(void *data, size_t size, + RIL_Token token); +#else +int ril_request_registration_state(void *data, size_t size, RIL_Token token); +#endif +#if RIL_VERSION >= 6 +int ril_request_data_registration_state(void *data, size_t size, + RIL_Token token); +#else +int ril_request_gprs_registration_state(void *data, size_t size, + RIL_Token token); +#endif +int ipc_net_mode_sel(struct ipc_message *message); +int ril_request_get_preferred_network_type(void *data, size_t size, + RIL_Token token); +int ril_request_set_preferred_network_type(void *data, size_t size, + RIL_Token token); - pthread_mutex_t mutex; -}; +/* + * Sound + */ -extern struct ril_data ril_data; +int srs_snd_set_call_volume(struct srs_message *message); +int ril_request_set_mute(void *data, size_t size, RIL_Token token); +int srs_snd_set_call_audio_path(struct srs_message *message); +int srs_snd_set_call_clock_sync(struct srs_message *message); /* - * Dispatch functions + * Misc */ -void ipc_fmt_dispatch(struct ipc_message_info *info); -void ipc_rfs_dispatch(struct ipc_message_info *info); -void srs_dispatch(struct srs_message *message); +int ipc_misc_me_version(struct ipc_message *message); +int ril_request_baseband_version(void *data, size_t size, RIL_Token token); +int ipc_misc_me_imsi(struct ipc_message *message); +int ril_request_get_imsi(void *data, size_t size, RIL_Token token); +int ipc_misc_me_sn(struct ipc_message *message); +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 ipc_misc_time_info(struct ipc_message *message); +int ril_request_screen_state(void *data, size_t size, RIL_Token token); -/* GEN */ +/* + * OEM + */ -struct ipc_gen_phone_res_expect_info { - unsigned char aseq; - unsigned short command; - void (*func)(struct ipc_message_info *info); - int complete; - int abort; -}; +int ipc_svc_display_screen(struct ipc_message *message); +int ril_request_oem_hook_raw(void *data, size_t size, RIL_Token token); -int ipc_gen_phone_res_expect_register(unsigned char aseq, unsigned short command, - void (*func)(struct ipc_message_info *info), int complete, int abort); -void ipc_gen_phone_res_expect_unregister(struct ipc_gen_phone_res_expect_info *expect); -struct ipc_gen_phone_res_expect_info *ipc_gen_phone_res_expect_find_aseq(unsigned char aseq); -int ipc_gen_phone_res_expect_to_func(unsigned char aseq, unsigned short command, - void (*func)(struct ipc_message_info *info)); -int ipc_gen_phone_res_expect_to_complete(unsigned char aseq, unsigned short command); -int ipc_gen_phone_res_expect_to_abort(unsigned char aseq, unsigned short command); - -void ipc_gen_phone_res(struct ipc_message_info *info); - -/* PWR */ - -void ipc_pwr_phone_pwr_up(void); -void ipc_pwr_phone_reset(void); -void ipc_pwr_phone_state(struct ipc_message_info *info); -void ril_request_radio_power(RIL_Token t, void *data, int length); - -/* DISP */ - -void ril_request_signal_strength(RIL_Token t); -void ipc_disp_icon_info(struct ipc_message_info *info); -void ipc_disp_rssi_info(struct ipc_message_info *info); - -/* MISC */ - -void ril_request_get_imei(RIL_Token t); -void ril_request_get_imeisv(RIL_Token t); -void ipc_misc_me_sn(struct ipc_message_info *info); -void ril_request_baseband_version(RIL_Token t); -void ipc_misc_me_version(struct ipc_message_info *info); -void ril_request_get_imsi(RIL_Token t); -void ipc_misc_me_imsi(struct ipc_message_info *info); -void ipc_misc_time_info(struct ipc_message_info *info); - -/* SAT */ -void ril_request_report_stk_service_is_running(RIL_Token t); -void ipc_sat_proactive_cmd(struct ipc_message_info *info); -void ril_request_stk_send_terminal_response(RIL_Token t, void *data, size_t length); -void ril_request_stk_send_envelope_command(RIL_Token t, void *data, size_t length); -void ipc_sat_envelope_cmd(struct ipc_message_info *info); - -/* SS */ - -void ril_request_send_ussd(RIL_Token t, void *data, size_t datalen); -void ril_request_cancel_ussd(RIL_Token t, void *data, size_t datalen); -void ipc_ss_ussd(struct ipc_message_info *info); - -/* SEC */ - -struct ril_request_sim_io_info { - unsigned char command; - unsigned short fileid; - unsigned char p1; - unsigned char p2; - unsigned char p3; - void *data; - int length; +/* + * Data + */ - int waiting; +struct ril_data_connection { + unsigned int cid; RIL_Token token; -}; -void ril_state_update(ril_sim_state status); -void ipc_sec_sim_status(struct ipc_message_info *info); -void ril_request_get_sim_status(RIL_Token t); -void ipc_sec_sim_icc_type(struct ipc_message_info *info); -void ril_request_sim_io_next(void); -void ril_request_sim_io_complete(RIL_Token t, unsigned char command, unsigned short fileid, - unsigned char p1, unsigned char p2, unsigned char p3, void *data, int length); -void ril_request_sim_io(RIL_Token t, void *data, int length); -void ipc_sec_rsim_access(struct ipc_message_info *info); -void ipc_sec_sim_status_complete(struct ipc_message_info *info); -void ipc_sec_lock_info(struct ipc_message_info *info); -void ril_request_enter_sim_pin(RIL_Token t, void *data, size_t length); -void ril_request_change_sim_pin(RIL_Token t, void *data, size_t length); -void ril_request_enter_sim_puk(RIL_Token t, void *data, size_t length); -void ril_request_query_facility_lock(RIL_Token t, void *data, size_t length); -void ipc_sec_phone_lock(struct ipc_message_info *info); -void ipc_sec_phone_lock_complete(struct ipc_message_info *info); -void ril_request_set_facility_lock(RIL_Token t, void *data, size_t length); - -/* SVC */ - -typedef enum { - RIL_OEM_HOOK_TAG_SVC = 1, -} RIL_OEMHookTag; - -typedef enum { - RIL_OEM_COMMAND_SVC_ENTER_MODE = 1, - RIL_OEM_COMMAND_SVC_END_MODE = 2, - RIL_OEM_COMMAND_SVC_KEY = 3, -} RIL_OEMCommandSvc; - -typedef struct { - unsigned char tag; - unsigned char command; - unsigned short length; -} RIL_OEMHookHeader; - -typedef struct { - unsigned char mode; - unsigned char type; - unsigned char query; -} RIL_OEMHookSvcEnterMode; - -typedef struct { - unsigned char mode; -} RIL_OEMHookSvcEndMode; - -typedef struct { - unsigned char key; - unsigned char query; -} RIL_OEMHookSvcKey; - -struct ril_oem_hook_svc_session { - RIL_Token token; - void *display_screen; - size_t display_screen_length; + int enabled; + int attached; + + char *apn; + char *username; + char *password; + + char *iface; + char *ip; + char *gateway; + char *subnet_mask; + char *dns1; + char *dns2; }; -void ipc_svc_display_screen(struct ipc_message_info *info); -void ril_request_oem_hook_raw(RIL_Token t, void *data, int length); - -/* NET */ - -void ril_plmn_split(char *plmn_data, char **plmn, unsigned int *mcc, unsigned int *mnc); -void ril_plmn_string(char *plmn_data, char *response[3]); -unsigned char ril_plmn_act_get(char *plmn_data); -void ril_request_operator(RIL_Token t); -void ipc_net_current_plmn(struct ipc_message_info *message); -#if RIL_VERSION >= 6 -void ril_request_voice_registration_state(RIL_Token t); -void ril_request_data_registration_state(RIL_Token t); -#else -void ril_request_registration_state(RIL_Token t); -void ril_request_gprs_registration_state(RIL_Token t); -#endif -void ipc_net_regist(struct ipc_message_info *message); -void ril_request_query_available_networks(RIL_Token t); -void ipc_net_plmn_list(struct ipc_message_info *info); -void ril_request_get_preferred_network_type(RIL_Token t); -void ril_request_set_preferred_network_type(RIL_Token t, void *data, size_t length); -void ipc_net_mode_sel(struct ipc_message_info *info); -void ril_request_query_network_selection_mode(RIL_Token t); -void ipc_net_plmn_sel(struct ipc_message_info *info); -void ril_request_set_network_selection_automatic(RIL_Token t); -void ril_request_set_network_selection_manual(RIL_Token t, void *data, size_t length); - -/* SMS */ - -struct ipc_sms_incoming_msg_info { - char *pdu; - int length; - - unsigned char type; - unsigned char tpid; -}; +int ril_data_connection_register(unsigned int cid, char *apn, char *username, + char *password, char *iface); +int ril_data_connection_unregister(struct ril_data_connection *data_connection); +int ril_data_connection_flush(void); +struct ril_data_connection *ril_data_connection_find_cid(unsigned int cid); +struct ril_data_connection *ril_data_connection_find_token(RIL_Token token); +struct ril_data_connection *ril_data_connection_start(char *apn, char *username, + char *password); +int ril_data_connection_stop(struct ril_data_connection *data_connection); +int ril_data_connection_enable(struct ril_data_connection *data_connection); +int ril_data_connection_disable(struct ril_data_connection *data_connection); +int ipc_gprs_define_pdp_context_callback(struct ipc_message *message); +int ril_request_setup_data_call(void *data, size_t size, RIL_Token token); +int ipc_gprs_ps(struct ipc_message *message); +int ipc_gprs_pdp_context(struct ipc_message *message); +int ril_request_data_call_list(void *data, size_t size, RIL_Token token); +int ipc_gprs_pdp_context_callback(struct ipc_message *message); +int ril_request_deactivate_data_call(void *data, size_t size, RIL_Token token); +int ipc_gprs_ip_configuration(struct ipc_message *message); +int ipc_gprs_hsdpa_status(struct ipc_message *message); +int ipc_gprs_call_status(struct ipc_message *message); +int ril_request_last_data_call_fail_cause(void *data, size_t size, + RIL_Token token); -struct ril_request_send_sms_info { - char *pdu; - int pdu_length; - unsigned char *smsc; - int smsc_length; +/* + * RFS + */ - RIL_Token token; -}; +int ipc_rfs_nv_read_item(struct ipc_message *message); +int ipc_rfs_nv_write_item(struct ipc_message *message); -int ril_request_send_sms_register(char *pdu, int pdu_length, unsigned char *smsc, int smsc_length, RIL_Token t); -void ril_request_send_sms_unregister(struct ril_request_send_sms_info *send_sms); -struct ril_request_send_sms_info *ril_request_send_sms_info_find(void); -struct ril_request_send_sms_info *ril_request_send_sms_info_find_token(RIL_Token t); - -void ril_request_send_sms_next(void); -void ril_request_send_sms_complete(RIL_Token t, char *pdu, int pdu_length, unsigned char *smsc, int smsc_length); -void ril_request_send_sms(RIL_Token t, void *data, size_t length); -void ril_request_send_sms_expect_more(RIL_Token t, void *data, size_t length); -void ipc_sms_svc_center_addr(struct ipc_message_info *info); -void ipc_sms_send_msg_complete(struct ipc_message_info *info); -void ipc_sms_send_msg(struct ipc_message_info *info); - -int ipc_sms_incoming_msg_register(char *pdu, int length, unsigned char type, unsigned char tpid); -void ipc_sms_incoming_msg_unregister(struct ipc_sms_incoming_msg_info *incoming_msg); -struct ipc_sms_incoming_msg_info *ipc_sms_incoming_msg_info_find(void); - -void ipc_sms_incoming_msg_complete(char *pdu, int length, unsigned char type, unsigned char tpid); -void ipc_sms_incoming_msg(struct ipc_message_info *info); -void ril_request_sms_acknowledge(RIL_Token t, void *data, size_t length); -void ipc_sms_deliver_report(struct ipc_message_info *info); - -void ril_request_write_sms_to_sim(RIL_Token token, void *data, size_t size); -void ipc_sms_save_msg(struct ipc_message_info *info); -void ril_request_delete_sms_on_sim(RIL_Token token, void *data, size_t size); -void ipc_sms_del_msg(struct ipc_message_info *info); - -int ril_sms_send(char *number, char *message); - -void ipc_sms_device_ready(struct ipc_message_info *info); - -/* Call */ - -void ipc_call_incoming(struct ipc_message_info *info); -void ipc_call_status(struct ipc_message_info *info); -void ril_request_dial(RIL_Token t, void *data, size_t length); -void ril_request_get_current_calls(RIL_Token t); -void ipc_call_list(struct ipc_message_info *info); -void ril_request_hangup(RIL_Token t); -void ril_request_answer(RIL_Token t); -void ril_request_last_call_fail_cause(RIL_Token t); -void ril_request_dtmf(RIL_Token t, void *data, int length); -void ipc_call_burst_dtmf(struct ipc_message_info *info); -void ril_request_dtmf_start(RIL_Token t, void *data, int length); -void ril_request_dtmf_stop(RIL_Token t); - -/* SND */ - -void ril_request_set_mute(RIL_Token t, void *data, int length); -void srs_snd_set_call_clock_sync(struct srs_message *message); -void srs_snd_set_call_volume(struct srs_message *message); -void srs_snd_set_call_audio_path(struct srs_message *message); - -/* GPRS */ - -struct ril_gprs_connection { - int cid; - int enabled; -#if RIL_VERSION >= 6 - RIL_DataCallFailCause fail_cause; -#else - RIL_LastDataCallActivateFailCause fail_cause; -#endif - char *interface; +/* + * GEN + */ - RIL_Token token; - struct ipc_gprs_pdp_context_set context; - struct ipc_gprs_define_pdp_context define_context; - struct ipc_gprs_ip_configuration ip_configuration; +struct ipc_gen_phone_res_expect { + unsigned char aseq; + unsigned short command; + int (*callback)(struct ipc_message *message); + int complete; + int abort; }; -int ril_gprs_connection_register(int cid); -void ril_gprs_connection_unregister(struct ril_gprs_connection *gprs_connection); -struct ril_gprs_connection *ril_gprs_connection_find_cid(int cid); -struct ril_gprs_connection *ril_gprs_connection_find_token(RIL_Token t); -struct ril_gprs_connection *ril_gprs_connection_start(void); -void ril_gprs_connection_stop(struct ril_gprs_connection *gprs_connection); - -void ril_request_setup_data_call(RIL_Token t, void *data, int length); -void ril_request_deactivate_data_call(RIL_Token t, void *data, int length); -void ipc_gprs_ip_configuration(struct ipc_message_info *info); -void ipc_gprs_call_status(struct ipc_message_info *info); -void ril_request_last_data_call_fail_cause(RIL_Token t); -void ipc_gprs_pdp_context(struct ipc_message_info *info); -void ril_unsol_data_call_list_changed(void); -void ril_request_data_call_list(RIL_Token t); - -/* RFS */ - -void ipc_rfs_nv_read_item(struct ipc_message_info *info); -void ipc_rfs_nv_write_item(struct ipc_message_info *info); +int ipc_gen_phone_res_expect_register(struct ril_client *client, + unsigned char aseq, unsigned short command, + int (*callback)(struct ipc_message *message), + int complete, int abort); +int ipc_gen_phone_res_expect_unregister(struct ril_client *client, + struct ipc_gen_phone_res_expect *expect); +int ipc_gen_phone_res_expect_flush(struct ril_client *client); +struct ipc_gen_phone_res_expect *ipc_gen_phone_res_expect_find_aseq(struct ril_client *client, + unsigned char aseq); +int ipc_gen_phone_res_expect_callback(unsigned char aseq, unsigned short command, + int (*callback)(struct ipc_message *message)); +int ipc_gen_phone_res_expect_complete(unsigned char aseq, unsigned short command); +int ipc_gen_phone_res_expect_abort(unsigned char aseq, unsigned short command); +int ipc_gen_phone_res(struct ipc_message *message); #endif @@ -1,166 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#define LOG_TAG "RIL-SAT" -#include <utils/Log.h> - -#include "samsung-ril.h" -#include "util.h" - -void ril_request_report_stk_service_is_running(RIL_Token t) -{ -#ifndef DISABLE_STK - ril_request_complete(t, RIL_E_SUCCESS, NULL, 0); -#else - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -#endif -} - -void ipc_sat_proactive_cmd_unsol(struct ipc_message_info *info) -{ - char *hexdata; - int length; - - if (info->data == NULL || info->length < 2) - return; - - length = (info->length - 2); - hexdata = (char *) calloc(1, length * 2 + 1); - - bin2hex((unsigned char *) info->data + 2, length, hexdata); - - ril_request_unsolicited(RIL_UNSOL_STK_PROACTIVE_COMMAND, hexdata, sizeof(char *)); - - free(hexdata); -} - -void ipc_sat_proactive_cmd_sol(struct ipc_message_info *info) -{ - unsigned char sw1, sw2; - - if (info->data == NULL || info->length < 2 * sizeof(unsigned char)) - goto error; - - sw1 = ((unsigned char*) info->data)[0]; - sw2 = ((unsigned char*) info->data)[1]; - - if (sw1 == 0x90 && sw2 == 0x00) { - ril_request_unsolicited(RIL_UNSOL_STK_SESSION_END, NULL, 0); - } else { - RIL_LOGE("%s: unhandled response sw1=%02x sw2=%02x", __func__, sw1, sw2); - } - - return; - -error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_sat_proactive_cmd(struct ipc_message_info *info) -{ - if (info->type == IPC_TYPE_INDI) { - ipc_sat_proactive_cmd_unsol(info); - } else if (info->type == IPC_TYPE_RESP) { - ipc_sat_proactive_cmd_sol(info); - } else { - RIL_LOGE("%s: unhandled proactive command response type %d",__func__, info->type); - } -} - -void ril_request_stk_send_terminal_response(RIL_Token t, void *data, size_t length) -{ - unsigned char buffer[264]; - int size; - - if (data == NULL || length < sizeof(char *)) - goto error; - - size = strlen(data) / 2; - if (size > 255) { - RIL_LOGE("%s: data exceeds maximum length", __func__); - goto error; - } - - memset(buffer, 0, sizeof(buffer)); - - buffer[0] = (unsigned char) size; - hex2bin(data, strlen(data), &buffer[1]); - - ipc_fmt_send(IPC_SAT_PROACTIVE_CMD, IPC_TYPE_GET, buffer, sizeof(buffer), ril_request_get_id(t)); - - ril_request_complete(t, RIL_E_SUCCESS, buffer, sizeof(char *)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_stk_send_envelope_command(RIL_Token t, void *data, size_t length) -{ - unsigned char buffer[264]; - int size; - - if (data == NULL || length < sizeof(char *)) - goto error; - - size = strlen(data) / 2; - if (size > 255) { - RIL_LOGE("%s: data exceeds maximum length", __func__); - goto error; - } - - memset(buffer, 0, sizeof(buffer)); - - buffer[0] = (unsigned char) size; - hex2bin(data, strlen(data), &buffer[1]); - - ipc_fmt_send(IPC_SAT_ENVELOPE_CMD, IPC_TYPE_EXEC, buffer, sizeof(buffer), ril_request_get_id(t)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_sat_envelope_cmd(struct ipc_message_info *info) -{ - char *hexdata; - int size; - - if (info->data == NULL || info->length < 2) - goto error; - - size = (info->length - 2); - hexdata = (char *) calloc(1, size * 2 + 1); - - bin2hex((unsigned char *) info->data + 2, size, hexdata); - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, hexdata, sizeof(char *)); - - free(hexdata); - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - @@ -1,981 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#define LOG_TAG "RIL-SEC" -#include <utils/Log.h> - -#include "samsung-ril.h" -#include "util.h" - -#include <sim.h> - -ril_sim_state ipc2ril_sim_state(struct ipc_sec_sim_status_response *pin_status) -{ - if (pin_status == NULL) - return -EINVAL; - - switch (pin_status->status) { - case IPC_SEC_SIM_STATUS_LOCK_SC: - switch (pin_status->facility_lock) { - case IPC_SEC_FACILITY_LOCK_TYPE_SC_UNLOCKED: - return SIM_STATE_READY; - case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ: - return SIM_STATE_PIN; - case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ: - return SIM_STATE_PUK; - case IPC_SEC_FACILITY_LOCK_TYPE_SC_CARD_BLOCKED: - return SIM_STATE_BLOCKED; - default: - RIL_LOGE("Unknown SIM facility lock: 0x%x", pin_status->facility_lock); - return SIM_STATE_ABSENT; - } - break; - case IPC_SEC_SIM_STATUS_LOCK_FD: - return SIM_STATE_ABSENT; - case IPC_SEC_SIM_STATUS_LOCK_PN: - return SIM_STATE_NETWORK_PERSO; - case IPC_SEC_SIM_STATUS_LOCK_PU: - return SIM_STATE_NETWORK_SUBSET_PERSO; - case IPC_SEC_SIM_STATUS_LOCK_PP: - return SIM_STATE_SERVICE_PROVIDER_PERSO; - case IPC_SEC_SIM_STATUS_LOCK_PC: - return SIM_STATE_CORPORATE_PERSO; - case IPC_SEC_SIM_STATUS_READY: - case IPC_SEC_SIM_STATUS_INIT_COMPLETE: - case IPC_SEC_SIM_STATUS_PB_INIT_COMPLETE: - return SIM_STATE_READY; - case IPC_SEC_SIM_STATUS_SIM_LOCK_REQUIRED: - case IPC_SEC_SIM_STATUS_INSIDE_PF_ERROR: - case IPC_SEC_SIM_STATUS_CARD_NOT_PRESENT: - case IPC_SEC_SIM_STATUS_CARD_ERROR: - return SIM_STATE_ABSENT; - default: - RIL_LOGE("Unknown SIM status: 0x%x", pin_status->status); - return SIM_STATE_ABSENT; - } -} - -void ril_state_update(ril_sim_state sim_state) -{ - RIL_RadioState radio_state; - - ril_data.state.sim_state = sim_state; - - switch (sim_state) { - case SIM_STATE_READY: -#if RIL_VERSION >= 7 - radio_state = RADIO_STATE_ON; -#else - radio_state = RADIO_STATE_SIM_READY; -#endif - break; - case SIM_STATE_NOT_READY: - radio_state = RADIO_STATE_SIM_NOT_READY; - break; - case SIM_STATE_ABSENT: - case SIM_STATE_PIN: - case SIM_STATE_PUK: - case SIM_STATE_BLOCKED: - case SIM_STATE_NETWORK_PERSO: - case SIM_STATE_NETWORK_SUBSET_PERSO: - case SIM_STATE_CORPORATE_PERSO: - case SIM_STATE_SERVICE_PROVIDER_PERSO: - radio_state = RADIO_STATE_SIM_LOCKED_OR_ABSENT; - break; - default: - radio_state = RADIO_STATE_SIM_NOT_READY; - break; - } - - ril_radio_state_update(radio_state); -} - -#if RIL_VERSION >= 6 -void ipc2ril_card_status(struct ipc_sec_sim_status_response *pin_status, RIL_CardStatus_v6 *card_status) -#else -void ipc2ril_card_status(struct ipc_sec_sim_status_response *pin_status, RIL_CardStatus *card_status) -#endif -{ - ril_sim_state sim_state; - int app_status_array_length; - int app_index; - int i; - - if (pin_status == NULL || card_status == NULL) - return; - - static RIL_AppStatus app_status_array[] = { - /* SIM_ABSENT = 0 */ - { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN, - NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, - /* SIM_NOT_READY = 1 */ - { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN, - NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, - /* SIM_READY = 2 */ - { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY, - NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, - /* SIM_PIN = 3 */ - { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN, - NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, - /* SIM_PUK = 4 */ - { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, - NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN }, - /* SIM_BLOCKED = 4 */ - { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, - NULL, NULL, 0, RIL_PINSTATE_ENABLED_PERM_BLOCKED, RIL_PINSTATE_UNKNOWN }, - /* SIM_NETWORK_PERSO = 6 */ - { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK, - NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, - /* SIM_NETWORK_SUBSET_PERSO = 7 */ - { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET, - NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, - /* SIM_CORPORATE_PERSO = 8 */ - { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_CORPORATE, - NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, - /* SIM_SERVICE_PROVIDER_PERSO = 9 */ - { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER, - NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, - }; - - app_status_array_length = sizeof(app_status_array) / sizeof(RIL_AppStatus); - - if (app_status_array_length > RIL_CARD_MAX_APPS) - app_status_array_length = RIL_CARD_MAX_APPS; - - sim_state = ipc2ril_sim_state(pin_status); - - /* Card is assumed to be present if not explicitly absent */ - if (sim_state == SIM_STATE_ABSENT) { - card_status->card_state = RIL_CARDSTATE_ABSENT; - } else { - card_status->card_state = RIL_CARDSTATE_PRESENT; - } - - // FIXME: How do we know that? - card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN; - - // Initialize the apps - for (i = 0 ; i < app_status_array_length ; i++) { - memcpy((void *) &(card_status->applications[i]), (void *) &(app_status_array[i]), sizeof(RIL_AppStatus)); - } - for (i = app_status_array_length ; i < RIL_CARD_MAX_APPS ; i++) { - memset((void *) &(card_status->applications[i]), 0, sizeof(RIL_AppStatus)); - } - - // sim_state corresponds to the app index on the table - card_status->gsm_umts_subscription_app_index = (int) sim_state; - card_status->cdma_subscription_app_index = (int) sim_state; - card_status->num_applications = app_status_array_length; - - RIL_LOGD("Selecting application #%d on %d", (int) sim_state, app_status_array_length); -} - -void ril_tokens_pin_status_dump(void) -{ - RIL_LOGD("ril_tokens_pin_status_dump:\n\ - \tril_data.tokens.pin_status = %p\n", ril_data.tokens.pin_status); -} - -void ipc_sec_sim_status(struct ipc_message_info *info) -{ - struct ipc_sec_sim_status_response *pin_status; - RIL_Token t; -#if RIL_VERSION >= 6 - RIL_CardStatus_v6 card_status; -#else - RIL_CardStatus card_status; -#endif - ril_sim_state sim_state; - - if (info->data == NULL || info->length < sizeof(struct ipc_sec_sim_status_response)) - goto error; - - pin_status = (struct ipc_sec_sim_status_response *) info->data; - t = ril_request_get_token(info->aseq); - - switch (info->type) { - case IPC_TYPE_NOTI: - if (ril_radio_state_complete(RADIO_STATE_OFF, RIL_TOKEN_NULL)) - return; - - RIL_LOGD("Got UNSOL PIN status message"); - - if (ril_data.tokens.pin_status != RIL_TOKEN_NULL && ril_data.tokens.pin_status != RIL_TOKEN_DATA_WAITING) { - RIL_LOGE("Another PIN status Req is in progress, skipping"); - return; - } - - sim_state = ipc2ril_sim_state(pin_status); - ril_state_update(sim_state); - - memcpy(&(ril_data.state.sim_pin_status), pin_status, sizeof(struct ipc_sec_sim_status_response)); - - ril_data.tokens.pin_status = RIL_TOKEN_DATA_WAITING; - ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); - break; - case IPC_TYPE_RESP: - RIL_LOGD("Got SOL PIN status message"); - - if (ril_data.tokens.pin_status != t) - RIL_LOGE("PIN status tokens mismatch"); - - sim_state = ipc2ril_sim_state(pin_status); - ril_state_update(sim_state); - - // Better keeping this up to date - memcpy(&(ril_data.state.sim_pin_status), pin_status, sizeof(struct ipc_sec_sim_status_response)); - - ipc2ril_card_status(pin_status, &card_status); - ril_request_complete(t, RIL_E_SUCCESS, &card_status, sizeof(card_status)); - - if (ril_data.tokens.pin_status != RIL_TOKEN_DATA_WAITING) - ril_data.tokens.pin_status = RIL_TOKEN_NULL; - break; - default: - RIL_LOGE("%s: unhandled ipc method: %d", __func__, info->type); - break; - } - - ril_tokens_pin_status_dump(); - - return; - -error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_get_sim_status(RIL_Token t) -{ - struct ipc_sec_sim_status_response *pin_status; -#if RIL_VERSION >= 6 - RIL_CardStatus_v6 card_status; -#else - RIL_CardStatus card_status; -#endif - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - if (ril_data.tokens.pin_status == RIL_TOKEN_DATA_WAITING) { - RIL_LOGD("Got RILJ request for UNSOL data"); - hex_dump(&(ril_data.state.sim_pin_status), sizeof(struct ipc_sec_sim_status_response)); - pin_status = &(ril_data.state.sim_pin_status); - - ipc2ril_card_status(pin_status, &card_status); - - ril_request_complete(t, RIL_E_SUCCESS, &card_status, sizeof(card_status)); - - ril_data.tokens.pin_status = RIL_TOKEN_NULL; - } else if (ril_data.tokens.pin_status == RIL_TOKEN_NULL) { - RIL_LOGD("Got RILJ request for SOL data"); - - /* Request data to the modem */ - ril_data.tokens.pin_status = t; - - ipc_fmt_send_get(IPC_SEC_SIM_STATUS, ril_request_get_id(t)); - } else { - RIL_LOGE("Another request is going on, returning UNSOL data"); - - pin_status = &(ril_data.state.sim_pin_status); - - ipc2ril_card_status(pin_status, &card_status); - ril_request_complete(t, RIL_E_SUCCESS, &card_status, sizeof(card_status)); - } - - ril_tokens_pin_status_dump(); -} - -void ipc_sec_sim_icc_type(struct ipc_message_info *info) -{ - struct ipc_sec_sim_icc_type *sim_icc_type; - - if (info->data == NULL || info->length < sizeof(struct ipc_sec_sim_icc_type)) - goto error; - - sim_icc_type = (struct ipc_sec_sim_icc_type *) info->data; - - memcpy(&ril_data.state.sim_icc_type, sim_icc_type, sizeof(struct ipc_sec_sim_icc_type)); - - return; - -error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -/* - * SIM I/O - */ - -int ril_request_sim_io_register(RIL_Token t, unsigned char command, unsigned short fileid, - unsigned char p1, unsigned char p2, unsigned char p3, void *data, int length, - struct ril_request_sim_io_info **sim_io_p) -{ - struct ril_request_sim_io_info *sim_io; - struct list_head *list_end; - struct list_head *list; - - sim_io = calloc(1, sizeof(struct ril_request_sim_io_info)); - if (sim_io == NULL) - return -1; - - sim_io->command = command; - sim_io->fileid = fileid; - sim_io->p1 = p1; - sim_io->p2 = p2; - sim_io->p3 = p3; - sim_io->data = data; - sim_io->length = length; - sim_io->waiting = 1; - sim_io->token = t; - - list_end = ril_data.sim_io; - while (list_end != NULL && list_end->next != NULL) - list_end = list_end->next; - - list = list_head_alloc((void *) sim_io, list_end, NULL); - - if (ril_data.sim_io == NULL) - ril_data.sim_io = list; - - if (sim_io_p != NULL) - *sim_io_p = sim_io; - - return 0; -} - -void ril_request_sim_io_unregister(struct ril_request_sim_io_info *sim_io) -{ - struct list_head *list; - - if (sim_io == NULL) - return; - - list = ril_data.sim_io; - while (list != NULL) { - if (list->data == (void *) sim_io) { - memset(sim_io, 0, sizeof(struct ril_request_sim_io_info)); - free(sim_io); - - if (list == ril_data.sim_io) - ril_data.sim_io = list->next; - - list_head_free(list); - - break; - } -list_continue: - list = list->next; - } -} - -struct ril_request_sim_io_info *ril_request_sim_io_info_find(void) -{ - struct ril_request_sim_io_info *sim_io; - struct list_head *list; - - list = ril_data.sim_io; - while (list != NULL) { - sim_io = (struct ril_request_sim_io_info *) list->data; - if (sim_io == NULL) - goto list_continue; - - return sim_io; - -list_continue: - list = list->next; - } - - return NULL; -} - -struct ril_request_sim_io_info *ril_request_sim_io_info_find_token(RIL_Token t) -{ - struct ril_request_sim_io_info *sim_io; - struct list_head *list; - - list = ril_data.sim_io; - while (list != NULL) { - sim_io = (struct ril_request_sim_io_info *) list->data; - if (sim_io == NULL) - goto list_continue; - - if (sim_io->token == t) - return sim_io; - -list_continue: - list = list->next; - } - - return NULL; -} - -void ril_request_sim_io_info_clear(struct ril_request_sim_io_info *sim_io) -{ - if (sim_io == NULL) - return; - - if (sim_io->data != NULL) - free(sim_io->data); -} - -void ril_request_sim_io_next(void) -{ - struct ril_request_sim_io_info *sim_io; - int rc; - - ril_data.tokens.sim_io = RIL_TOKEN_NULL; - - sim_io = ril_request_sim_io_info_find(); - if (sim_io == NULL) - return; - - sim_io->waiting = 0; - ril_data.tokens.sim_io = sim_io->token; - - ril_request_sim_io_complete(sim_io->token, sim_io->command, sim_io->fileid, - sim_io->p1, sim_io->p2, sim_io->p3, sim_io->data, sim_io->length); - - if (sim_io->data != NULL) - free(sim_io->data); - sim_io->data = NULL; - sim_io->length = 0; -} - -void ril_request_sim_io_complete(RIL_Token t, unsigned char command, unsigned short fileid, - unsigned char p1, unsigned char p2, unsigned char p3, void *data, int length) -{ - struct ipc_sec_rsim_access_get *rsim_access = NULL; - void *rsim_access_data = NULL; - int rsim_access_length = 0; - - rsim_access_length += sizeof(struct ipc_sec_rsim_access_get); - - if (data != NULL && length > 0) - rsim_access_length += length; - - rsim_access_data = calloc(1, rsim_access_length); - rsim_access = (struct ipc_sec_rsim_access_get *) rsim_access_data; - - rsim_access->command = command; - rsim_access->fileid = fileid; - rsim_access->p1 = p1; - rsim_access->p2 = p2; - rsim_access->p3 = p3; - - if (data != NULL && length > 0) - memcpy((void *) ((int) rsim_access_data + sizeof(struct ipc_sec_rsim_access_get)), data, length); - - ipc_fmt_send(IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET, rsim_access_data, rsim_access_length, ril_request_get_id(t)); - - free(rsim_access_data); -} - -void ril_request_sim_io(RIL_Token t, void *data, int length) -{ - struct ril_request_sim_io_info *sim_io_info = NULL; -#if RIL_VERSION >= 6 - RIL_SIM_IO_v6 *sim_io = NULL; -#else - RIL_SIM_IO *sim_io = NULL; -#endif - void *sim_io_data = NULL; - int sim_io_data_length = 0; - int rc; - - if (data == NULL || length < (int) sizeof(*sim_io)) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_SIM_NOT_READY, t)) - return; - -#if RIL_VERSION >= 6 - sim_io = (RIL_SIM_IO_v6 *) data; -#else - sim_io = (RIL_SIM_IO *) data; -#endif - - // SIM IO data should be a string if present - if (sim_io->data != NULL) { - sim_io_data_length = strlen(sim_io->data) / 2; - if (sim_io_data_length > 0) { - sim_io_data = calloc(1, sim_io_data_length); - hex2bin(sim_io->data, sim_io_data_length * 2, sim_io_data); - } - } - - rc = ril_request_sim_io_register(t, sim_io->command, sim_io->fileid, - sim_io->p1, sim_io->p2, sim_io->p3, sim_io_data, sim_io_data_length, - &sim_io_info); - if (rc < 0 || sim_io_info == NULL) { - RIL_LOGE("Unable to add the request to the list"); - - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - if (sim_io_data != NULL) - free(sim_io_data); - - // Send the next SIM I/O in the list - ril_request_sim_io_next(); - } - - if (ril_data.tokens.sim_io != RIL_TOKEN_NULL) { - RIL_LOGD("Another SIM I/O is being processed, adding to the list"); - return; - } - - sim_io_info->waiting = 0; - ril_data.tokens.sim_io = t; - - ril_request_sim_io_complete(t, sim_io->command, sim_io->fileid, - sim_io->p1, sim_io->p2, sim_io->p3, sim_io_data, sim_io_data_length); - - if (sim_io_data != NULL) - free(sim_io_data); - sim_io_info->data = NULL; - sim_io_info->length = 0; - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_sec_rsim_access(struct ipc_message_info *info) -{ - struct ril_request_sim_io_info *sim_io_info; - struct sim_file_response sim_file_response; - RIL_SIM_IO_Response sim_io_response; - struct ipc_sec_rsim_access_response *rsim_access = NULL; - struct ipc_sec_rsim_access_response_data *rsim_data = NULL; - void *rsim_access_data = NULL; - char *sim_response = NULL; - unsigned char *buf = NULL; - int offset; - int i; - - if (info->data == NULL || info->length < sizeof(struct ipc_sec_rsim_access_response)) - goto error; - - sim_io_info = ril_request_sim_io_info_find_token(ril_request_get_token(info->aseq)); - if (sim_io_info == NULL) { - RIL_LOGE("Unable to find SIM I/O in the list!"); - - // Send the next SIM I/O in the list - ril_request_sim_io_next(); - - return; - } - - rsim_access = (struct ipc_sec_rsim_access_response *) info->data; - rsim_access_data = (void *) ((int) info->data + sizeof(struct ipc_sec_rsim_access_response)); - - memset(&sim_io_response, 0, sizeof(sim_io_response)); - sim_io_response.sw1 = rsim_access->sw1; - sim_io_response.sw2 = rsim_access->sw2; - - switch (sim_io_info->command) { - case SIM_COMMAND_READ_BINARY: - case SIM_COMMAND_READ_RECORD: - if (rsim_access->len <= 0) - break; - - // Copy the data as-is - sim_response = (char *) malloc(rsim_access->len * 2 + 1); - bin2hex(rsim_access_data, rsim_access->len, sim_response); - sim_io_response.simResponse = sim_response; - break; - case SIM_COMMAND_GET_RESPONSE: - if (rsim_access->len < sizeof(struct ipc_sec_rsim_access_response_data)) - break; - - // SIM ICC type 1 requires direct copy - if (ril_data.state.sim_icc_type.type == 1) { - sim_response = (char *) malloc(rsim_access->len * 2 + 1); - bin2hex(rsim_access_data, rsim_access->len, sim_response); - sim_io_response.simResponse = sim_response; - break; - } - - rsim_data = (struct ipc_sec_rsim_access_response_data *) - rsim_access_data; - - memset(&sim_file_response, 0, sizeof(sim_file_response)); - - buf = (unsigned char *) rsim_data; - buf += sizeof(struct ipc_sec_rsim_access_response_data); - buf += rsim_data->offset - 2; - if (((int) buf + 1 - (int) rsim_access_data) > rsim_access->len) - break; - - sim_file_response.file_id[0] = buf[0]; - sim_file_response.file_id[1] = buf[1]; - - buf = (unsigned char *) rsim_data; - buf += rsim_access->len - 2; - while ((int) buf > (int) rsim_data + 2) { - if (buf[0] == 0x88) { - buf -= 2; - break; - } - buf--; - } - - if ((int) buf <= (int) rsim_data + 2) - break; - - sim_file_response.file_size[0] = buf[0]; - sim_file_response.file_size[1] = buf[1]; - - // Fallback to EF - sim_file_response.file_type = SIM_FILE_TYPE_EF; - for (i = 0 ; i < sim_file_ids_count ; i++) { - if (sim_io_info->fileid == sim_file_ids[i].file_id) { - sim_file_response.file_type = sim_file_ids[i].type; - break; - } - } - - 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 (rsim_data->file_structure) { - case IPC_SEC_RSIM_FILE_STRUCTURE_TRANSPARENT: - sim_file_response.file_structure = SIM_FILE_STRUCTURE_TRANSPARENT; - break; - case IPC_SEC_RSIM_FILE_STRUCTURE_LINEAR_FIXED: - default: - sim_file_response.file_structure = SIM_FILE_STRUCTURE_LINEAR_FIXED; - break; - } - - sim_file_response.record_length = rsim_data->record_length; - - sim_response = (char *) malloc(sizeof(struct sim_file_response) * 2 + 1); - bin2hex((void *) &sim_file_response, sizeof(struct sim_file_response), sim_response); - sim_io_response.simResponse = sim_response; - break; - case SIM_COMMAND_UPDATE_BINARY: - case SIM_COMMAND_UPDATE_RECORD: - case SIM_COMMAND_SEEK: - default: - sim_io_response.simResponse = NULL; - break; - } - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, &sim_io_response, sizeof(sim_io_response)); - - if (sim_io_response.simResponse != NULL) { - RIL_LOGD("SIM response: %s", sim_io_response.simResponse); - free(sim_io_response.simResponse); - } - - ril_request_sim_io_unregister(sim_io_info); - - // Send the next SIM I/O in the list - ril_request_sim_io_next(); - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_sec_sim_status_complete(struct ipc_message_info *info) -{ - struct ipc_gen_phone_res *phone_res; - int attempts = -1; - int rc; - - phone_res = (struct ipc_gen_phone_res *) info->data; - - rc = ipc_gen_phone_res_check(phone_res); - if (rc < 0) { - if ((phone_res->code & 0x00ff) == 0x10) { - RIL_LOGE("Wrong password!"); - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_PASSWORD_INCORRECT, &attempts, sizeof(attempts)); - } else if ((phone_res->code & 0x00ff) == 0x0c) { - RIL_LOGE("Wrong password and no attempts left!"); - - attempts = 0; - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_PASSWORD_INCORRECT, &attempts, sizeof(attempts)); - - ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); - } else { - RIL_LOGE("There was an error during pin status complete!"); - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - } - return; - } - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, &attempts, sizeof(attempts)); -} - -void ipc_sec_lock_info(struct ipc_message_info *info) -{ - struct ipc_sec_lock_info_response *lock_info; - int attempts; - - if (info->data == NULL || info->length < sizeof(struct ipc_sec_lock_info_response)) - return; - - lock_info = (struct ipc_sec_lock_info_response *) info->data; - - /* - * FIXME: solid way of handling lockinfo and sim unlock response together - * so we can return the number of attempts left in respondSecPinStatus - */ - - if (lock_info->type == IPC_SEC_PIN_TYPE_PIN1) { - attempts = lock_info->attempts; - RIL_LOGD("%s: PIN1 %d attempts left", __func__, attempts); - } else { - RIL_LOGE("%s: unhandled lock type %d", __func__, lock_info->type); - } -} - -void ril_request_enter_sim_pin(RIL_Token t, void *data, size_t length) -{ - struct ipc_sec_pin_status_set pin_status; - char *pin = ((char **) data)[0]; - unsigned char buf[9]; - - if (data == NULL || length < (int) sizeof(char *)) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - // 1. Send PIN - if (strlen(data) > 16) { - RIL_LOGE("%s: pin exceeds maximum length", __func__); - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - } - - ipc_sec_pin_status_set_setup(&pin_status, IPC_SEC_PIN_TYPE_PIN1, pin, NULL); - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SEC_SIM_STATUS, ipc_sec_sim_status_complete); - - ipc_fmt_send_set(IPC_SEC_SIM_STATUS, ril_request_get_id(t), (unsigned char *) &pin_status, sizeof(pin_status)); - - // 2. Get lock status - // FIXME: This is not clean at all - memset(buf, 0, sizeof(buf)); - buf[0] = 1; - buf[1] = IPC_SEC_PIN_TYPE_PIN1; - - ipc_fmt_send(IPC_SEC_LOCK_INFO, IPC_TYPE_GET, buf, sizeof(buf), ril_request_get_id(t)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_change_sim_pin(RIL_Token t, void *data, size_t length) -{ - char *password_old; - char *password_new; - struct ipc_sec_change_locking_pw_set locking_pw; - - if (data == NULL || length < (int) (2 * sizeof(char *))) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_SIM_NOT_READY, t)) - return; - - password_old = ((char **) data)[0]; - password_new = ((char **) data)[1]; - - memset(&locking_pw, 0, sizeof(locking_pw)); - - locking_pw.facility = IPC_SEC_SIM_STATUS_LOCK_SC; - - locking_pw.length_new = strlen(password_new) > sizeof(locking_pw.password_new) - ? sizeof(locking_pw.password_new) - : strlen(password_new); - - memcpy(locking_pw.password_new, password_new, locking_pw.length_new); - - locking_pw.length_old = strlen(password_old) > sizeof(locking_pw.password_old) - ? sizeof(locking_pw.password_old) - : strlen(password_old); - - memcpy(locking_pw.password_old, password_old, locking_pw.length_old); - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SEC_CHANGE_LOCKING_PW, - ipc_sec_sim_status_complete); - - ipc_fmt_send_set(IPC_SEC_CHANGE_LOCKING_PW, ril_request_get_id(t), (unsigned char *) &locking_pw, sizeof(locking_pw)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_enter_sim_puk(RIL_Token t, void *data, size_t length) -{ - struct ipc_sec_pin_status_set pin_status; - char *puk; - char *pin; - - if (data == NULL || length < (int) (2 * sizeof(char *))) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - puk = ((char **) data)[0]; - pin = ((char **) data)[1]; - - ipc_sec_pin_status_set_setup(&pin_status, IPC_SEC_PIN_TYPE_PIN1, pin, puk); - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SEC_SIM_STATUS, - ipc_sec_sim_status_complete); - - ipc_fmt_send_set(IPC_SEC_SIM_STATUS, ril_request_get_id(t), (unsigned char *) &pin_status, sizeof(pin_status)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_sec_phone_lock(struct ipc_message_info *info) -{ - int status; - struct ipc_sec_phone_lock_response *lock; - - if (info->data == NULL || info->length < sizeof(struct ipc_sec_phone_lock_response)) - goto error; - - lock = (struct ipc_sec_phone_lock_response *) info->data; - status = lock->status; - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, &status, sizeof(status)); - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_query_facility_lock(RIL_Token t, void *data, size_t length) -{ - struct ipc_sec_phone_lock_get lock_request; - char *facility; - - if (data == NULL || length < sizeof(char *)) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_SIM_NOT_READY, t)) - return; - - facility = ((char **) data)[0]; - - if (!strcmp(facility, "SC")) { - lock_request.facility = IPC_SEC_FACILITY_TYPE_SC; - } else if (!strcmp(facility, "FD")) { - lock_request.facility = IPC_SEC_FACILITY_TYPE_FD; - } else if (!strcmp(facility, "PN")) { - lock_request.facility = IPC_SEC_FACILITY_TYPE_PN; - } else if (!strcmp(facility, "PU")) { - lock_request.facility = IPC_SEC_FACILITY_TYPE_PU; - } else if (!strcmp(facility, "PP")) { - lock_request.facility = IPC_SEC_FACILITY_TYPE_PP; - } else if (!strcmp(facility, "PC")) { - lock_request.facility = IPC_SEC_FACILITY_TYPE_PC; - } else { - RIL_LOGE("%s: unsupported facility: %s", __func__, facility); - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - } - - ipc_fmt_send(IPC_SEC_PHONE_LOCK, IPC_TYPE_GET, (void *) &lock_request, sizeof(lock_request), ril_request_get_id(t)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -// Both functions were the same -#define ipc_sec_phone_lock_complete \ - ipc_sec_sim_status_complete - -void ril_request_set_facility_lock(RIL_Token t, void *data, size_t length) -{ - struct ipc_sec_phone_lock_set lock_request; - char *facility; - char *lock; - char *password; - char *class; - - if (data == NULL || length < (int) (4 * sizeof(char *))) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_SIM_NOT_READY, t)) - return; - - facility = ((char **) data)[0]; - lock = ((char **) data)[1]; - password = ((char **) data)[2]; - class = ((char **) data)[3]; - - memset(&lock_request, 0, sizeof(lock_request)); - - if (!strcmp(facility, "SC")) { - lock_request.type = IPC_SEC_SIM_STATUS_LOCK_SC; - } else if (!strcmp(facility, "FD")) { - lock_request.type = IPC_SEC_SIM_STATUS_LOCK_FD; - } else if (!strcmp(facility, "PN")) { - lock_request.type = IPC_SEC_SIM_STATUS_LOCK_PN; - } else if (!strcmp(facility, "PU")) { - lock_request.type = IPC_SEC_SIM_STATUS_LOCK_PU; - } else if (!strcmp(facility, "PP")) { - lock_request.type = IPC_SEC_SIM_STATUS_LOCK_PP; - } else if (!strcmp(facility, "PC")) { - lock_request.type = IPC_SEC_SIM_STATUS_LOCK_PC; - } else { - RIL_LOGE("%s: unsupported facility: %s", __func__, facility); - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - } - - lock_request.lock = lock[0] == '1' ? 1 : 0; - lock_request.length = strlen(password) > sizeof(lock_request.password) - ? sizeof(lock_request.password) - : strlen(password); - - memcpy(lock_request.password, password, lock_request.length); - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SEC_PHONE_LOCK, - ipc_sec_phone_lock_complete); - - ipc_fmt_send(IPC_SEC_PHONE_LOCK, IPC_TYPE_SET, (void *) &lock_request, sizeof(lock_request), ril_request_get_id(t)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} @@ -0,0 +1,1303 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> + * + * Samsung-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. + * + * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> + +#define LOG_TAG "RIL" +#include <utils/Log.h> + +#include <samsung-ril.h> +#include <utils.h> +#include <sim.h> + +#if RIL_VERSION >= 6 +RIL_RadioState ipc2ril_sec_pin_status_response(struct ipc_sec_pin_status_response_data *data, + RIL_CardStatus_v6 *card_status) +#else +RIL_RadioState ipc2ril_sec_pin_status_response(struct ipc_sec_pin_status_response_data *data, + RIL_CardStatus *card_status) +#endif +{ + 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_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, + // Ready + { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, + // PIN lock + { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + // PUK lock + { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN }, + // PUK locked + { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_PERM_BLOCKED, RIL_PINSTATE_UNKNOWN }, + // Perso network + { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + // Perso network subset + { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + // Perso corporate + { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_CORPORATE, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + // Perso service provider + { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + }; + RIL_RadioState radio_state; + unsigned int index; + unsigned int count; + unsigned int i; + + if (data == NULL || card_status == NULL) + return 0; + + count = sizeof(app_statuses) / sizeof(RIL_AppStatus); + + switch (data->status) { + case IPC_SEC_PIN_STATUS_LOCK_SC: + switch (data->facility_lock) { + case IPC_SEC_FACILITY_LOCK_TYPE_SC_UNLOCKED: + index = 2; + break; + case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ: + index = 3; + break; + case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ: + index = 4; + break; + case IPC_SEC_FACILITY_LOCK_TYPE_SC_CARD_BLOCKED: + index = 5; + break; + default: + index = 0; + break; + } + break; + case IPC_SEC_PIN_STATUS_LOCK_FD: + index = 0; + break; + case IPC_SEC_PIN_STATUS_LOCK_PN: + index = 6; + break; + case IPC_SEC_PIN_STATUS_LOCK_PU: + index = 7; + break; + case IPC_SEC_PIN_STATUS_LOCK_PP: + index = 9; + break; + case IPC_SEC_PIN_STATUS_LOCK_PC: + index = 8; + break; + case IPC_SEC_PIN_STATUS_READY: + case IPC_SEC_PIN_STATUS_INIT_COMPLETE: + case IPC_SEC_PIN_STATUS_PB_INIT_COMPLETE: + index = 2; + break; + case IPC_SEC_PIN_STATUS_SIM_LOCK_REQUIRED: + case IPC_SEC_PIN_STATUS_INSIDE_PF_ERROR: + case IPC_SEC_PIN_STATUS_CARD_NOT_PRESENT: + case IPC_SEC_PIN_STATUS_CARD_ERROR: + default: + index = 0; + break; + } + + 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; + } + +#if RIL_VERSION >= 6 + memset(card_status, 0, sizeof(RIL_CardStatus_v6)); +#else + memset(card_status, 0, sizeof(RIL_CardStatus)); +#endif + + 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; +#if RIL_VERSION >= 7 + card_status->ims_subscription_app_index = -1; +#endif + + 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; +} + +unsigned char ril2ipc_sec_facility_type(char *facility) +{ + if (facility == NULL) + return 0; + + if (!strcmp(facility, "SC")) + return IPC_SEC_FACILITY_TYPE_SC; + else if (!strcmp(facility, "FD")) + return IPC_SEC_FACILITY_TYPE_FD; + else if (!strcmp(facility, "PN")) + return IPC_SEC_FACILITY_TYPE_PN; + else if (!strcmp(facility, "PU")) + return IPC_SEC_FACILITY_TYPE_PU; + else if (!strcmp(facility, "PP")) + return IPC_SEC_FACILITY_TYPE_PP; + else if (!strcmp(facility, "PC")) + return IPC_SEC_FACILITY_TYPE_PC; + else + return 0; +} + +int ipc_sec_pin_status_callback(struct ipc_message *message) +{ + struct ipc_gen_phone_res_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; + + data = (struct ipc_gen_phone_res_data *) message->data; + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) { + // Return the original SIM status + ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); + } else { + // Destroy the original SIM status + ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS); + } + + return 0; +} + +int ipc_sec_pin_status(struct ipc_message *message) +{ + struct ipc_sec_pin_status_response_data *data; + struct ipc_sec_pin_status_request_data request_data; +#if RIL_VERSION >= 6 + RIL_CardStatus_v6 card_status; +#else + RIL_CardStatus card_status; +#endif + RIL_RadioState radio_state; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_pin_status_response_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + data = (struct ipc_sec_pin_status_response_data *) message->data; + + radio_state = ipc2ril_sec_pin_status_response(data, &card_status); + if (radio_state == 0) + return 0; + + if (card_status.applications[0].app_type == RIL_APPTYPE_SIM && card_status.applications[0].app_state == RIL_APPSTATE_PIN && ril_data->sim_pin != NULL) { + ril_request_data_set_uniq(RIL_REQUEST_GET_SIM_STATUS, (void *) &card_status, sizeof(card_status)); + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1, ril_data->sim_pin, NULL); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS); + return 0; + } + + rc = ipc_gen_phone_res_expect_callback(message->aseq, IPC_SEC_PIN_STATUS, ipc_sec_pin_status_callback); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS); + return 0; + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS); + return 0; + } + + return 0; + } + + ril_radio_state_update(radio_state); + + if (message->type == IPC_TYPE_RESP && ipc_seq_valid(message->aseq)) { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &card_status, sizeof(card_status)); + } else { + ril_request_data_set_uniq(RIL_REQUEST_GET_SIM_STATUS, (void *) &card_status, sizeof(card_status)); + ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); + } + + return 0; +} + +int ril_request_get_sim_status(void *data, size_t size, RIL_Token token) +{ + void *card_status_data; + size_t card_status_size; +#if RIL_VERSION >= 6 + RIL_CardStatus_v6 *card_status; +#else + RIL_CardStatus *card_status; +#endif + 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; + + card_status_size = ril_request_data_size_get(RIL_REQUEST_GET_SIM_STATUS); + card_status_data = ril_request_data_get(RIL_REQUEST_GET_SIM_STATUS); + +#if RIL_VERSION >= 6 + if (card_status_data != NULL && card_status_size >= sizeof(RIL_CardStatus_v6)) { + card_status = (RIL_CardStatus_v6 *) ril_request_data_get(RIL_REQUEST_GET_SIM_STATUS); +#else + if (card_status_data != NULL && card_status_size >= sizeof(RIL_CardStatus)) { + card_status = (RIL_CardStatus *) ril_request_data_get(RIL_REQUEST_GET_SIM_STATUS); +#endif + ril_request_complete(token, RIL_E_SUCCESS, card_status_data, card_status_size); + + free(card_status_data); + + return RIL_REQUEST_COMPLETED; + } else { + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_GET, NULL, 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + return RIL_REQUEST_HANDLED; + } +} + +int ipc_sec_phone_lock(struct ipc_message *message) +{ + struct ipc_sec_phone_lock_response_data *data; + int active; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_phone_lock_response_data)) + return -1; + + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; + + data = (struct ipc_sec_phone_lock_response_data *) message->data; + + active = !!data->active; + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &active, sizeof(active)); + + return 0; +} + +int ril_request_query_facility_lock(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_phone_lock_request_get_data request_data; + char **values = NULL; + 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; + + values = (char **) data; + + request_data.facility_type = ril2ipc_sec_facility_type(values[0]); + if (request_data.facility_type == 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PHONE_LOCK, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_sec_callback(struct ipc_message *message) +{ + struct ipc_sec_lock_infomation_request_data request_data; + struct ipc_gen_phone_res_data *data; + struct ril_request *request = NULL; + void *request_complete_data; + size_t request_complete_size; + unsigned char facility_type; + char **values; + int retry_count; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; + + data = (struct ipc_gen_phone_res_data *) message->data; + + request = ril_request_find_token(ipc_fmt_request_token(message->aseq)); + if (request == NULL) + goto error; + + if (request->request == RIL_REQUEST_ENTER_SIM_PIN || request->request == RIL_REQUEST_CHANGE_SIM_PIN) { + // Grab the count of remaining tries before completing the request + + ril_request_data_set_uniq(request->request, (void *) data, sizeof(struct ipc_gen_phone_res_data)); + + rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_LOCK_INFOMATION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } else if (request->request == RIL_REQUEST_ENTER_SIM_PIN2 || request->request == RIL_REQUEST_CHANGE_SIM_PIN2) { + // Grab the count of remaining tries before completing the request + + ril_request_data_set_uniq(request->request, (void *) data, sizeof(struct ipc_gen_phone_res_data)); + + rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_LOCK_INFOMATION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } else if (request->request == RIL_REQUEST_SET_FACILITY_LOCK) { + values = (char **) request->data; + + request_complete_size = ril_request_data_size_get(RIL_REQUEST_SET_FACILITY_LOCK); + request_complete_data = ril_request_data_get(RIL_REQUEST_SET_FACILITY_LOCK); + + rc = ipc_gen_phone_res_check(data); + + if (request_complete_data != NULL && request_complete_size > 0 && rc >= 0) { + rc = ipc_gen_phone_res_expect_callback(message->aseq, IPC_SEC_PHONE_LOCK, ipc_sec_callback); + if (rc < 0) { + strings_array_free(values, request->size); + goto error; + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_PHONE_LOCK, IPC_TYPE_SET, request_complete_data, request_complete_size); + if (rc < 0) { + strings_array_free(values, request->size); + goto error; + } + } else { + // When FD facility PIN2 unlock failed, ask the count of remaining tries directly + + facility_type = ril2ipc_sec_facility_type(values[0]); + + strings_array_free(values, request->size); + + // Grab the count of remaining tries before completing the request + + ril_request_data_set_uniq(RIL_REQUEST_SET_FACILITY_LOCK, (void *) data, sizeof(struct ipc_gen_phone_res_data)); + + if (facility_type == IPC_SEC_FACILITY_TYPE_FD) { + rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } else { + rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_LOCK_INFOMATION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } + } else if (request->request == RIL_REQUEST_SIM_IO) { + request_complete_size = ril_request_data_size_get(RIL_REQUEST_SIM_IO); + request_complete_data = ril_request_data_get(RIL_REQUEST_SIM_IO); + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) { + ril_request_complete(request->token, RIL_E_SIM_PIN2, NULL, 0); + goto complete; + } + + if (request_complete_data != NULL && request_complete_size > 0) { + rc = ipc_fmt_send(message->aseq, IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET, request_complete_data, request_complete_size); + if (rc < 0) + goto error; + } else { + goto error; + } + } else { + retry_count = -1; + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) { + if ((data->code & 0xff) == 0x10) { + RIL_LOGE("%s: Wrong password", __func__); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count)); + } else if ((data->code & 0xff) == 0x0c) { + RIL_LOGE("%s: Wrong password and no attempts left", __func__); + retry_count = 0; + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count)); + } else { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, &retry_count, sizeof(retry_count)); + } + } else { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &retry_count, sizeof(retry_count)); + } + } + + if (request->request == RIL_REQUEST_ENTER_SIM_PUK || request->request == RIL_REQUEST_ENTER_SIM_PUK2) + ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); + + goto complete; + +error: + if (request != NULL) + ril_request_complete(request->token, RIL_E_GENERIC_FAILURE, NULL, 0); + +complete: + return 0; +} + +int ril_request_set_facility_lock(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_phone_lock_request_set_data request_data; + struct ipc_sec_pin_status_request_data pin_request_data; + struct ril_request *request; + unsigned char facility_type; + unsigned char active; + char **values = NULL; + 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; + + request = ril_request_find_request_status(RIL_REQUEST_SET_FACILITY_LOCK, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + facility_type = ril2ipc_sec_facility_type(values[0]); + if (facility_type == 0) + goto error; + + active = values[1][0] == '1'; + + rc = ipc_sec_phone_lock_request_set_setup(&request_data, facility_type, active, values[2]); + if (rc < 0) + goto error; + + if (facility_type == IPC_SEC_FACILITY_TYPE_FD) { + // FD facility requires PIN2 unlock first + + rc = ipc_sec_pin_status_setup(&pin_request_data, IPC_SEC_PIN_TYPE_PIN2, values[2], NULL); + if (rc < 0) + goto error; + + ril_request_data_set_uniq(RIL_REQUEST_SET_FACILITY_LOCK, &request_data, sizeof(request_data)); + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_SET_FACILITY_LOCK); + goto error; + } + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &pin_request_data, sizeof(pin_request_data)); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_SET_FACILITY_LOCK); + goto error; + } + + rc = RIL_REQUEST_HANDLED; + goto complete; + } + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PHONE_LOCK, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PHONE_LOCK, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_enter_sim_pin(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_pin_status_request_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 2 * sizeof(char *) || ril_data == NULL) + goto error; + + 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_ENTER_SIM_PIN, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + if (values[0] == NULL) + goto error; + + if (ril_data->sim_pin != NULL) + free(ril_data->sim_pin); + + ril_data->sim_pin = strdup(values[0]); + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1, values[0], NULL); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_enter_sim_puk(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_pin_status_request_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 2 * sizeof(char *)) + goto error; + + 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_ENTER_SIM_PUK, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1, values[1], values[0]); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_enter_sim_pin2(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_pin_status_request_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 2 * sizeof(char *)) + goto error; + + 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_ENTER_SIM_PIN2, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2, values[0], NULL); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_enter_sim_puk2(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_pin_status_request_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 2 * sizeof(char *)) + goto error; + + 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_ENTER_SIM_PUK2, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2, values[1], values[0]); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_change_sim_pin(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_change_locking_pw_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 3 * sizeof(char *)) + goto error; + + request = ril_request_find_request_status(RIL_REQUEST_CHANGE_SIM_PIN, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_change_locking_pw_setup(&request_data, IPC_SEC_FACILITY_TYPE_SC, values[0], values[1]); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_change_sim_pin2(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_change_locking_pw_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 3 * sizeof(char *)) + goto error; + + request = ril_request_find_request_status(RIL_REQUEST_CHANGE_SIM_PIN, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_change_locking_pw_setup(&request_data, IPC_SEC_FACILITY_TYPE_FD, values[0], values[1]); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_sec_rsim_access(struct ipc_message *message) +{ + struct ipc_sec_rsim_access_response_header *header; + struct ipc_sec_rsim_access_usim_response_header *usim_header; + struct sim_file_response sim_file_response; + struct ril_request *request; + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + RIL_SIM_IO_Response response; +#if RIL_VERSION >= 6 + RIL_SIM_IO_v6 *sim_io; +#else + RIL_SIM_IO *sim_io; +#endif + unsigned char *p; + unsigned int offset; + unsigned int i; + void *data; + size_t size; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_rsim_access_response_header)) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return 0; + + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + + header = (struct ipc_sec_rsim_access_response_header *) message->data; + + size = ipc_sec_rsim_access_size_extract(message->data, message->size); + data = ipc_sec_rsim_access_extract(message->data, message->size); + + request = ril_request_find_token(ipc_fmt_request_token(message->aseq)); +#if RIL_VERSION >= 6 + if (request == NULL || request->data == NULL || request->size < sizeof(RIL_SIM_IO_v6)) +#else + if (request == NULL || request->data == NULL || request->size < sizeof(RIL_SIM_IO)) +#endif + return 0; + +#if RIL_VERSION >= 6 + sim_io = (RIL_SIM_IO_v6 *) request->data; +#else + sim_io = (RIL_SIM_IO *) request->data; +#endif + + memset(&response, 0, sizeof(response)); + response.sw1 = header->sw1; + response.sw2 = header->sw2; + + switch (sim_io->command) { + case SIM_COMMAND_READ_BINARY: + case SIM_COMMAND_READ_RECORD: + if (header->length == 0) + break; + + response.simResponse = data2string(data, header->length); + break; + case SIM_COMMAND_GET_RESPONSE: + if (header->length == 0) + break; + + if (ipc_fmt_data->sim_icc_type_data.type == 0x01) { + response.simResponse = data2string(data, header->length); + break; + } + + if (header->length < sizeof(struct ipc_sec_rsim_access_usim_response_header)) + break; + + usim_header = (struct ipc_sec_rsim_access_usim_response_header *) data; + + memset(&sim_file_response, 0, sizeof(sim_file_response)); + + offset = sizeof(struct ipc_sec_rsim_access_usim_response_header) + usim_header->offset; + if (offset > header->length) + break; + + offset = usim_header->offset - 2; + p = (unsigned char *) usim_header + offset; + + sim_file_response.file_id[0] = p[0]; + sim_file_response.file_id[1] = p[1]; + + offset = header->length - 2; + p = (unsigned char *) usim_header; + + while (offset > 2) { + if (p[offset] == 0x88) { + offset -= 2; + break; + } + + offset--; + } + + if (offset <= 2) + break; + + p = (unsigned char *) usim_header + offset; + + sim_file_response.file_size[0] = p[0]; + sim_file_response.file_size[1] = p[1]; + + // Fallback to EF + sim_file_response.file_type = SIM_FILE_TYPE_EF; + for (i = 0; i < sim_file_ids_count; i++) { + if (sim_io->fileid == sim_file_ids[i].file_id) { + sim_file_response.file_type = sim_file_ids[i].type; + break; + } + } + + 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 (usim_header->file_structure) { + case IPC_SEC_RSIM_FILE_STRUCTURE_TRANSPARENT: + sim_file_response.file_structure = SIM_FILE_STRUCTURE_TRANSPARENT; + break; + case IPC_SEC_RSIM_FILE_STRUCTURE_LINEAR_FIXED: + default: + sim_file_response.file_structure = SIM_FILE_STRUCTURE_LINEAR_FIXED; + break; + } + + sim_file_response.record_length = usim_header->length; + + response.simResponse = data2string((void *) &sim_file_response, sizeof(sim_file_response)); + break; + case SIM_COMMAND_UPDATE_BINARY: + case SIM_COMMAND_UPDATE_RECORD: + case SIM_COMMAND_SEEK: + default: + response.simResponse = NULL; + break; + } + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &response, sizeof(response)); + + if (response.simResponse != NULL) + free(response.simResponse); + + return 0; +} + +int ril_request_sim_io(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_rsim_access_request_header request_header; + struct ipc_sec_pin_status_request_data pin_request_data; + struct ril_request *request; +#if RIL_VERSION >= 6 + RIL_SIM_IO_v6 *sim_io = NULL; +#else + RIL_SIM_IO *sim_io = NULL; +#endif + void *sim_io_data = NULL; + size_t sim_io_size = 0; + void *request_data = NULL; + size_t request_size = 0; + int pin_request = 0; + int rc; + +#if RIL_VERSION >= 6 + if (data == NULL || size < sizeof(RIL_SIM_IO_v6)) +#else + if (data == NULL || size < sizeof(RIL_SIM_IO)) +#endif + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_SIM_IO, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + +#if RIL_VERSION >= 6 + sim_io = (RIL_SIM_IO_v6 *) data; +#else + sim_io = (RIL_SIM_IO *) data; +#endif + + if (sim_io->data != NULL) { + sim_io_size = string2data_size(sim_io->data); + if (sim_io_size == 0) + goto error; + + sim_io_data = string2data(sim_io->data); + if (sim_io_data == NULL) + goto error; + } + + if (sim_io->pin2 != NULL) { + // PIN2 unlock first + + pin_request = 1; + + rc = ipc_sec_pin_status_setup(&pin_request_data, IPC_SEC_PIN_TYPE_PIN2, sim_io->pin2, NULL); + if (rc < 0) + goto error; + } + + 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 RIL_VERSION >= 6 + if (sim_io->aidPtr != NULL) + free(sim_io->aidPtr); +#endif + + memset(&request_header, 0, sizeof(request_header)); + request_header.command = sim_io->command; + request_header.file_id = sim_io->fileid; + request_header.p1 = sim_io->p1; + request_header.p2 = sim_io->p2; + request_header.p3 = sim_io->p3; + + sim_io = NULL; + + request_size = ipc_sec_rsim_access_size_setup(&request_header, sim_io_data, sim_io_size); + if (request_size == 0) + goto error; + + request_data = ipc_sec_rsim_access_setup(&request_header, sim_io_data, sim_io_size); + if (request_data == NULL) + goto error; + + if (pin_request) { + // PIN2 unlock first + + ril_request_data_set_uniq(RIL_REQUEST_SIM_IO, request_data, request_size); + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_SIM_IO); + goto error; + } + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &pin_request_data, sizeof(pin_request_data)); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_SIM_IO); + goto error; + } + + rc = RIL_REQUEST_HANDLED; + goto complete; + } + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET, request_data, request_size); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + 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 RIL_VERSION >= 6 + if (sim_io->aidPtr != NULL) + free(sim_io->aidPtr); +#endif + } + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + if (sim_io_data != NULL && sim_io_size > 0) + free(sim_io_data); + + if (request_data != NULL && request_size > 0) + free(request_data); + + return rc; +} + +int ipc_sec_sim_icc_type(struct ipc_message *message) +{ + struct ipc_sec_sim_icc_type_data *data; + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_sim_icc_type_data)) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return 0; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + + data = (struct ipc_sec_sim_icc_type_data *) message->data; + + if (ipc_fmt_data->sim_icc_type_data.type != data->type) + ipc_fmt_data->sim_icc_type_data.type = data->type; + + return 0; +} + +int ipc_sec_lock_infomation(struct ipc_message *message) +{ + struct ipc_sec_lock_infomation_response_data *data; + struct ipc_gen_phone_res_data *gen_phone_res; + int requests[] = { RIL_REQUEST_ENTER_SIM_PIN, RIL_REQUEST_CHANGE_SIM_PIN, RIL_REQUEST_ENTER_SIM_PIN2, RIL_REQUEST_CHANGE_SIM_PIN2, RIL_REQUEST_SET_FACILITY_LOCK }; + void *gen_phone_res_data = NULL; + size_t gen_phone_res_size = 0; + int retry_count; + unsigned int count; + unsigned int i; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_lock_infomation_response_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; + + data = (struct ipc_sec_lock_infomation_response_data *) message->data; + if (data->type != IPC_SEC_PIN_TYPE_PIN1 && data->type != IPC_SEC_PIN_TYPE_PIN2) + return 0; + + count = sizeof(requests) / sizeof(int); + + for (i = 0; i < count; i++) { + gen_phone_res_size = ril_request_data_size_get(requests[i]); + if (gen_phone_res_size < sizeof(struct ipc_gen_phone_res_data)) + continue; + + gen_phone_res_data = ril_request_data_get(requests[i]); + if (gen_phone_res_data == NULL) + continue; + + break; + } + + if (gen_phone_res_data == NULL || gen_phone_res_size < sizeof(struct ipc_gen_phone_res_data)) + return 0; + + gen_phone_res = (struct ipc_gen_phone_res_data *) gen_phone_res_data; + + retry_count = data->retry_count; + + rc = ipc_gen_phone_res_check(gen_phone_res); + if (rc < 0) { + if ((gen_phone_res->code & 0xff) == 0x10) { + RIL_LOGE("%s: Wrong password and %d attempts left", __func__, retry_count); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count)); + } else if ((gen_phone_res->code & 0xff) == 0x0c) { + RIL_LOGE("%s: Wrong password and no attempts left", __func__); + retry_count = 0; + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count)); + } else { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, &retry_count, sizeof(retry_count)); + } + } else { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &retry_count, sizeof(retry_count)); + } + + free(gen_phone_res_data); + + return 0; +} @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,18 +18,20 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ -#define LOG_TAG "RIL-SMS" +#include <stdlib.h> + +#define LOG_TAG "RIL" #include <utils/Log.h> -#include "samsung-ril.h" -#include "util.h" +#include <samsung-ril.h> +#include <utils.h> -unsigned short ril2ipc_sms_ack_error(int success, int failcause) +unsigned short ril2ipc_sms_ack(int success, int fail_cause) { if (success) { return IPC_SMS_ACK_NO_ERROR; } else { - switch (failcause) { + switch (fail_cause) { case 0xD3: return IPC_SMS_ACK_PDA_FULL_ERROR; default: @@ -38,25 +40,29 @@ unsigned short ril2ipc_sms_ack_error(int success, int failcause) } } -RIL_Errno ipc2ril_sms_ack_error(unsigned short error, int *error_code) +RIL_Errno ipc2ril_sms_ack_error(unsigned short ack) { - // error_code is defined in See 3GPP 27.005, 3.2.5 for GSM/UMTS - - if (error_code == NULL) - return RIL_E_GENERIC_FAILURE; - - switch (error) { + switch (ack) { case IPC_SMS_ACK_NO_ERROR: - *error_code = -1; return RIL_E_SUCCESS; default: - // unknown error - *error_code = 500; return RIL_E_GENERIC_FAILURE; } } -unsigned char ril2ipc_sms_save_msg_status(int status) +int ipc2ril_sms_ack_error_code(unsigned short ack) +{ + // Error code is defined in 3GPP 27.005, 3.2.5 for GSM/UMTS + + switch (ack) { + case IPC_SMS_ACK_NO_ERROR: + return -1; + default: + return 500; + } +} + +unsigned char ril2ipc_sms_status(int status) { switch (status) { case 0: @@ -68,851 +74,550 @@ unsigned char ril2ipc_sms_save_msg_status(int status) case 3: return IPC_SMS_STATUS_STO_SENT; default: - return IPC_SMS_STATUS_REC_READ; + return 0; } } -/* - * Outgoing SMS functions - */ - -int ril_request_send_sms_register(char *pdu, int pdu_length, unsigned char *smsc, int smsc_length, RIL_Token t) +int ipc_sms_send_msg(struct ipc_message *message) { - struct ril_request_send_sms_info *send_sms; - struct list_head *list_end; - struct list_head *list; + struct ipc_sms_send_msg_response_data *data; + RIL_SMS_Response response; - send_sms = calloc(1, sizeof(struct ril_request_send_sms_info)); - if (send_sms == NULL) + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sms_send_msg_response_data)) return -1; - send_sms->pdu = pdu; - send_sms->pdu_length = pdu_length; - send_sms->smsc = smsc; - send_sms->smsc_length = smsc_length; - send_sms->token = t; + if (!ipc_seq_valid(message->aseq)) + return 0; - list_end = ril_data.outgoing_sms; - while (list_end != NULL && list_end->next != NULL) - list_end = list_end->next; + data = (struct ipc_sms_send_msg_response_data *) message->data; - list = list_head_alloc((void *) send_sms, list_end, NULL); + memset(&response, 0, sizeof(response)); + response.messageRef = data->id; + response.ackPDU = NULL; - if (ril_data.outgoing_sms == NULL) - ril_data.outgoing_sms = list; + ril_request_complete(ipc_fmt_request_token(message->aseq), ipc2ril_sms_ack_error(data->ack), &response, sizeof(response)); return 0; } -void ril_request_send_sms_unregister(struct ril_request_send_sms_info *send_sms) -{ - struct list_head *list; - - if (send_sms == NULL) - return; - - list = ril_data.outgoing_sms; - while (list != NULL) { - if (list->data == (void *) send_sms) { - memset(send_sms, 0, sizeof(struct ril_request_send_sms_info)); - free(send_sms); - - if (list == ril_data.outgoing_sms) - ril_data.outgoing_sms = list->next; - - list_head_free(list); - - break; - } -list_continue: - list = list->next; - } -} - -struct ril_request_send_sms_info *ril_request_send_sms_info_find(void) -{ - struct ril_request_send_sms_info *send_sms; - struct list_head *list; - - list = ril_data.outgoing_sms; - while (list != NULL) { - send_sms = (struct ril_request_send_sms_info *) list->data; - if (send_sms == NULL) - goto list_continue; - - return send_sms; - -list_continue: - list = list->next; - } - - return NULL; -} - -struct ril_request_send_sms_info *ril_request_send_sms_info_find_token(RIL_Token t) -{ - struct ril_request_send_sms_info *send_sms; - struct list_head *list; - - list = ril_data.outgoing_sms; - while (list != NULL) { - send_sms = (struct ril_request_send_sms_info *) list->data; - if (send_sms == NULL) - goto list_continue; - - if (send_sms->token == t) - return send_sms; - -list_continue: - list = list->next; - } - - return NULL; -} - -void ril_request_send_sms_info_clear(struct ril_request_send_sms_info *send_sms) -{ - if (send_sms == NULL) - return; - - if (send_sms->pdu != NULL) - free(send_sms->pdu); - - if (send_sms->smsc != NULL) - free(send_sms->smsc); -} - -void ril_request_send_sms_next(void) -{ - struct ril_request_send_sms_info *send_sms; - RIL_Token t; - char *pdu; - int pdu_length; - unsigned char *smsc; - int smsc_length; - int rc; - - ril_data.tokens.outgoing_sms = RIL_TOKEN_NULL; - - send_sms = ril_request_send_sms_info_find(); - if (send_sms == NULL) - return; - - t = send_sms->token; - pdu = send_sms->pdu; - pdu_length = send_sms->pdu_length; - smsc = send_sms->smsc; - smsc_length = send_sms->smsc_length; - - ril_request_send_sms_unregister(send_sms); - - if (pdu == NULL) { - RIL_LOGE("SMS send request has no valid PDU"); - if (smsc != NULL) - free(smsc); - return; - } - - ril_data.tokens.outgoing_sms = t; - if (smsc == NULL) { - // We first need to get SMS SVC before sending the message - RIL_LOGD("We have no SMSC, let's ask one"); - - rc = ril_request_send_sms_register(pdu, pdu_length, NULL, 0, t); - if (rc < 0) { - RIL_LOGE("Unable to add the request to the list"); - - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - if (pdu != NULL) - free(pdu); - // Send the next SMS in the list - ril_request_send_sms_next(); - } - - ipc_fmt_send_get(IPC_SMS_SVC_CENTER_ADDR, ril_request_get_id(t)); - } else { - ril_request_send_sms_complete(t, pdu, pdu_length, smsc, smsc_length); - if (pdu != NULL) - free(pdu); - if (smsc != NULL) - free(smsc); - } -} - -void ril_request_send_sms_complete(RIL_Token t, char *pdu, int pdu_length, unsigned char *smsc, int smsc_length) +int ril_request_send_sms_complete(unsigned char seq, const void *smsc, + size_t smsc_size, const void *pdu, size_t pdu_size) { - struct ipc_sms_send_msg_request send_msg; - unsigned char send_msg_type; - - unsigned char *pdu_hex; - int pdu_hex_length; - - void *data; - int length; - + struct ipc_sms_send_msg_request_header request_header; + unsigned int count; + unsigned int index; + void *data = NULL; + size_t size = 0; unsigned char *p; + int rc; - if (pdu == NULL || pdu_length <= 0 || smsc == NULL || smsc_length <= 0) - goto error; - - if ((pdu_length / 2 + smsc_length) > 0xfe) { - RIL_LOGE("PDU or SMSC too large, aborting"); - goto error; - } - - pdu_hex_length = pdu_length % 2 == 0 ? pdu_length / 2 : - (pdu_length ^ 1) / 2; + if (smsc == NULL || smsc_size == 0 || pdu == NULL || pdu_size == 0) + return -1; - // Length of the final message - length = sizeof(send_msg) + pdu_hex_length + smsc_length; + if (!ipc_seq_valid(seq)) + return -1; - RIL_LOGD("Sending SMS message (length: 0x%x)!", length); + memset(&request_header, 0, sizeof(request_header)); + request_header.type = IPC_SMS_TYPE_OUTGOING; + request_header.msg_type = IPC_SMS_MSG_TYPE_SINGLE; - pdu_hex = calloc(1, pdu_hex_length); - hex2bin(pdu, pdu_length, pdu_hex); - send_msg_type = IPC_SMS_MSG_SINGLE; + p = (unsigned char *) pdu; - /* PDU operations */ - int pdu_tp_da_index = 2; - unsigned char pdu_tp_da_len = pdu_hex[pdu_tp_da_index]; + // PDU TP-DA length + p += 2; - if (pdu_tp_da_len > 0xff / 2) { - RIL_LOGE("PDU TP-DA Len failed (0x%x)\n", pdu_tp_da_len); - goto pdu_end; + if (*p > (255 / 2)) { + RIL_LOGE("PDU TP-DA length failed (0x%x)", *p); + goto setup; } - RIL_LOGD("PDU TP-DA Len is 0x%x\n", pdu_tp_da_len); + // PDU TP-UDH length + p += *p; - int pdu_tp_udh_index = pdu_tp_da_index + pdu_tp_da_len; - unsigned char pdu_tp_udh_len = pdu_hex[pdu_tp_udh_index]; - - if (pdu_tp_udh_len > 0xff / 2 || pdu_tp_udh_len < 5) { - RIL_LOGE("PDU TP-UDH Len failed (0x%x)\n", pdu_tp_udh_len); - goto pdu_end; + if (*p > (255 / 2) || *p < 5) { + RIL_LOGE("PDU TP-UDH length failed (0x%x)", *p); + goto setup; } - RIL_LOGD("PDU TP-UDH Len is 0x%x\n", pdu_tp_udh_len); - - int pdu_tp_udh_num_index = pdu_tp_udh_index + 4; - unsigned char pdu_tp_udh_num = pdu_hex[pdu_tp_udh_num_index]; + // PDU TO-UDH count + p += 4; + count = (unsigned int) *p; - if (pdu_tp_udh_num > 0xf) { - RIL_LOGE("PDU TP-UDH Num failed (0x%x)\n", pdu_tp_udh_num); - goto pdu_end; + if (count > 0x0f) { + RIL_LOGE("PDU TP-UDH count failed (%d)", count); + goto setup; } - int pdu_tp_udh_seq_index = pdu_tp_udh_index + 5; - unsigned char pdu_tp_udh_seq = pdu_hex[pdu_tp_udh_seq_index]; + // PDU TO-UDH index + p += 1; + index = (unsigned int) *p; - if (pdu_tp_udh_seq > 0xf || pdu_tp_udh_seq > pdu_tp_udh_num) { - RIL_LOGE("PDU TP-UDH Seq failed (0x%x)\n", pdu_tp_udh_seq); - goto pdu_end; + if (index > count) { + RIL_LOGE("PDU TP-UDH index failed (%d)", index); + goto setup; } - RIL_LOGD("We are sending message %d on %d\n", pdu_tp_udh_seq, pdu_tp_udh_num); - - if (pdu_tp_udh_num > 1) { - RIL_LOGD("We are sending a multi-part message!"); - send_msg_type = IPC_SMS_MSG_MULTIPLE; + if (count > 1) { + request_header.msg_type = IPC_SMS_MSG_TYPE_MULTIPLE; + RIL_LOGD("Sending multi-part message %d/%d\n", index, count); } -pdu_end: - // Alloc memory for the final message - data = calloc(1, length); +setup: + size = ipc_sms_send_msg_size_setup(&request_header, smsc, smsc_size, pdu, pdu_size); + if (size == 0) + goto error; - // Clear and fill the IPC structure part of the message - memset(&send_msg, 0, sizeof(struct ipc_sms_send_msg_request)); - send_msg.type = IPC_SMS_TYPE_OUTGOING; - send_msg.msg_type = send_msg_type; - send_msg.length = (unsigned char) (pdu_hex_length + smsc_length + 1); - send_msg.smsc_len = smsc_length; + data = ipc_sms_send_msg_setup(&request_header, smsc, smsc_size, pdu, pdu_size); + if (data == NULL) + goto error; - // Copy the parts of the message - p = data; - memcpy(p, &send_msg, sizeof(send_msg)); - p += sizeof(send_msg); - memcpy(p, smsc, smsc_length); - p += smsc_length; - memcpy(p, pdu_hex, pdu_hex_length); + rc = ipc_gen_phone_res_expect_abort(seq, IPC_SMS_SEND_MSG); + if (rc < 0) + goto error; - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SMS_SEND_MSG, ipc_sms_send_msg_complete); + rc = ipc_fmt_send(seq, IPC_SMS_SEND_MSG, IPC_TYPE_EXEC, data, size); + if (rc < 0) + goto error; - ipc_fmt_send(IPC_SMS_SEND_MSG, IPC_TYPE_EXEC, data, length, ril_request_get_id(t)); + rc = 0; + goto complete; - free(pdu_hex); - free(data); +error: + rc = -1; - return; +complete: + if (data != NULL && size > 0) + free(data); -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - // Send the next SMS in the list - ril_request_send_sms_next(); + return rc; } -void ril_request_send_sms(RIL_Token t, void *data, size_t length) +int ril_request_send_sms(void *data, size_t size, RIL_Token token) { - char *pdu = NULL; - int pdu_length; - unsigned char *smsc = NULL; - int smsc_length; + struct ril_request *request; + char **values = NULL; + void *smsc = NULL; + size_t smsc_size = 0; + void *pdu = NULL; + size_t pdu_size = 0; + unsigned int i; int rc; - if (data == NULL || length < (int) (2 * sizeof(char *))) + if (data == NULL || size < 2 * sizeof(char *)) goto error; - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - pdu = ((char **) data)[1]; - smsc = ((unsigned char **) data)[0]; - pdu_length = 0; - smsc_length = 0; + request = ril_request_find_request_status(RIL_REQUEST_SEND_SMS, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - if (pdu != NULL) { - pdu_length = strlen(pdu) + 1; - pdu = strdup(pdu); - } - if (smsc != NULL) { - smsc_length = strlen((char *) smsc); - smsc = (unsigned char *) strdup((char *) smsc); - } + values = (char **) data; + if (values[1] == NULL) + goto error; - if (ril_data.tokens.outgoing_sms != RIL_TOKEN_NULL) { - RIL_LOGD("Another outgoing SMS is being processed, adding to the list"); + pdu_size = string2data_size(values[1]); + if (pdu_size == 0) + goto error; - rc = ril_request_send_sms_register(pdu, pdu_length, smsc, smsc_length, t); - if (rc < 0) { - RIL_LOGE("Unable to add the request to the list"); + pdu = string2data(values[1]); + if (pdu == NULL) + goto error; + + if (values[0] != NULL) { + smsc_size = string2data_size(values[0]); + if (smsc_size == 0) goto error; - } - return; + smsc = string2data(values[0]); + if (smsc == NULL) + goto error; } - ril_data.tokens.outgoing_sms = t; - if (smsc == NULL) { - // We first need to get SMS SVC before sending the message - RIL_LOGD("We have no SMSC, let's ask one"); + strings_array_free(values, size); + values = NULL; - rc = ril_request_send_sms_register(pdu, pdu_length, NULL, 0, t); + if (smsc != NULL && smsc_size > 0) { + rc = ril_request_send_sms_complete(ipc_fmt_request_seq(token), pdu, pdu_size, (void *) ((unsigned char *) smsc + sizeof(unsigned char)), ((unsigned char *) smsc)[0]); + if (rc < 0) + goto error; + } else { + ril_request_data_set_uniq(RIL_REQUEST_SEND_SMS, pdu, pdu_size); + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SMS_SVC_CENTER_ADDR, IPC_TYPE_GET, NULL, 0); if (rc < 0) { - RIL_LOGE("Unable to add the request to the list"); + ril_request_data_free(RIL_REQUEST_SEND_SMS); goto error; } - - ipc_fmt_send_get(IPC_SMS_SVC_CENTER_ADDR, ril_request_get_id(t)); - } else { - ril_request_send_sms_complete(t, pdu, pdu_length, smsc, smsc_length); - if (pdu != NULL) - free(pdu); - if (smsc != NULL) - free(smsc); } - return; + rc = RIL_REQUEST_HANDLED; + goto complete; error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - - if (pdu != NULL) - free(pdu); - if (smsc != NULL) - free(smsc); - // Send the next SMS in the list - ril_request_send_sms_next(); -} - -void ril_request_send_sms_expect_more(RIL_Token t, void *data, size_t length) -{ - // No particular treatment here, we already have a queue - ril_request_send_sms(t, data, length); -} + if (values != NULL) + strings_array_free(values, size); -void ipc_sms_svc_center_addr(struct ipc_message_info *info) -{ - struct ril_request_send_sms_info *send_sms; - RIL_Token t; - char *pdu; - int pdu_length; - unsigned char *smsc; - int smsc_length; - int rc; - - if (info->data == NULL || info->length < sizeof(unsigned char)) - goto error; + ril_request_complete(token, RIL_E_SMS_SEND_FAIL_RETRY, NULL, 0); - send_sms = ril_request_send_sms_info_find_token(ril_request_get_token(info->aseq)); - if (send_sms == NULL || send_sms->pdu == NULL || send_sms->pdu_length <= 0) { - RIL_LOGE("The request wasn't queued, reporting generic error!"); + rc = RIL_REQUEST_COMPLETED; - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - ril_request_send_sms_info_clear(send_sms); - ril_request_send_sms_unregister(send_sms); - // Send the next SMS in the list - ril_request_send_sms_next(); - - return; - } - - t = send_sms->token; - pdu = send_sms->pdu; - pdu_length = send_sms->pdu_length; - smsc = (unsigned char *) info->data + sizeof(unsigned char); - smsc_length = (int) ((unsigned char *) info->data)[0]; +complete: + if (smsc != NULL && smsc_size > 0) + free(smsc); - RIL_LOGD("Got SMSC, completing the request"); - ril_request_send_sms_unregister(send_sms); - ril_request_send_sms_complete(t, pdu, pdu_length, smsc, smsc_length); - if (pdu != NULL) + if (pdu != NULL && pdu_size > 0) free(pdu); - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_sms_send_msg_complete(struct ipc_message_info *info) -{ - struct ril_request_send_sms_info *send_sms; - struct ipc_gen_phone_res *phone_res; - - phone_res = (struct ipc_gen_phone_res *) info->data; - if (ipc_gen_phone_res_check(phone_res) < 0) { - RIL_LOGE("IPC_GEN_PHONE_RES indicates error, abort request to RILJ"); - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - // Send the next SMS in the list - ril_request_send_sms_next(); - } + return rc; } -void ipc_sms_send_msg(struct ipc_message_info *info) +int ipc_sms_incoming_msg(struct ipc_message *message) { - struct ipc_sms_send_msg_response *report_msg; - RIL_SMS_Response response; - RIL_Errno e; + struct ipc_sms_incoming_msg_header *header; + void *pdu; + size_t pdu_size; + char *pdu_string; - if (info->data == NULL || info->length < sizeof(struct ipc_sms_send_msg_response)) - goto error; + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sms_incoming_msg_header)) + return -1; - report_msg = (struct ipc_sms_send_msg_response *) info->data; + header = (struct ipc_sms_incoming_msg_header *) message->data; - RIL_LOGD("Got ACK for msg_tpid #%d\n", report_msg->msg_tpid); + pdu_size = ipc_sms_incoming_msg_pdu_size_extract(message->data, message->size); + if (pdu_size == 0) + return 0; - memset(&response, 0, sizeof(response)); - response.messageRef = report_msg->msg_tpid; - response.ackPDU = NULL; + pdu = ipc_sms_incoming_msg_pdu_extract(message->data, message->size); + if (pdu == NULL) + return 0; - e = ipc2ril_sms_ack_error(report_msg->error, &response.errorCode); + pdu_string = data2string(pdu, pdu_size); + if (pdu_string == NULL) + return 0; - ril_request_complete(ril_request_get_token(info->aseq), e, (void *) &response, sizeof(response)); + ril_request_data_set_uniq(RIL_REQUEST_SMS_ACKNOWLEDGE, &header->id, sizeof(header->id)); - // Send the next SMS in the list - ril_request_send_sms_next(); + if (header->type == IPC_SMS_TYPE_STATUS_REPORT) + ril_request_unsolicited(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, (void *) pdu_string, sizeof(pdu_string)); + else + ril_request_unsolicited(RIL_UNSOL_RESPONSE_NEW_SMS, (void *) pdu_string, sizeof(pdu_string)); - return; + free(pdu_string); -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return 0; } -/* - * Incoming SMS functions - */ - -int ipc_sms_incoming_msg_register(char *pdu, int length, unsigned char type, unsigned char tpid) +int ipc_sms_save_msg(struct ipc_message *message) { - struct ipc_sms_incoming_msg_info *incoming_msg; - struct list_head *list_end; - struct list_head *list; + struct ipc_sms_save_msg_response_data *data; - incoming_msg = calloc(1, sizeof(struct ipc_sms_incoming_msg_info)); - if (incoming_msg == NULL) + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sms_save_msg_response_data)) return -1; - incoming_msg->pdu = pdu; - incoming_msg->length = length; - incoming_msg->type = type; - incoming_msg->tpid = tpid; - - list_end = ril_data.incoming_sms; - while (list_end != NULL && list_end->next != NULL) - list_end = list_end->next; + if (!ipc_seq_valid(message->aseq)) + return 0; - list = list_head_alloc((void *) incoming_msg, list_end, NULL); + data = (struct ipc_sms_save_msg_response_data *) message->data; - if (ril_data.incoming_sms == NULL) - ril_data.incoming_sms = list; + if (data->error) + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + else + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); return 0; } -void ipc_sms_incoming_msg_unregister(struct ipc_sms_incoming_msg_info *incoming_msg) +int ril_request_write_sms_to_sim(void *data, size_t size, RIL_Token token) { - struct list_head *list; - - if (incoming_msg == NULL) - return; + struct ipc_sms_save_msg_request_header request_header; + RIL_SMS_WriteArgs *args = NULL; + void *smsc = NULL; + size_t smsc_size = 0; + void *pdu = NULL; + size_t pdu_size = 0; + void *request_data = NULL; + size_t request_size = 0; + int rc; - list = ril_data.incoming_sms; - while (list != NULL) { - if (list->data == (void *) incoming_msg) { - memset(incoming_msg, 0, sizeof(struct ipc_sms_incoming_msg_info)); - free(incoming_msg); + if (data == NULL || size < sizeof(RIL_SMS_WriteArgs)) + goto error; - if (list == ril_data.incoming_sms) - ril_data.incoming_sms = list->next; + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - list_head_free(list); + args = (RIL_SMS_WriteArgs *) data; + if (args->pdu == NULL) { + if (args->smsc != NULL) + free(args->smsc); - break; - } -list_continue: - list = list->next; + goto error; } -} -struct ipc_sms_incoming_msg_info *ipc_sms_incoming_msg_info_find(void) -{ - struct ipc_sms_incoming_msg_info *incoming_msg; - struct list_head *list; + memset(&request_header, 0, sizeof(request_header)); + request_header.status = ril2ipc_sms_status(args->status); - list = ril_data.incoming_sms; - while (list != NULL) { - incoming_msg = (struct ipc_sms_incoming_msg_info *) list->data; - if (incoming_msg == NULL) - goto list_continue; + pdu_size = string2data_size(args->pdu); + if (pdu_size == 0) { + free(args->pdu); - return incoming_msg; + if (args->smsc != NULL) + free(args->smsc); -list_continue: - list = list->next; + goto error; } - return NULL; -} - -void ipc_sms_incoming_msg_next(void) -{ - struct ipc_sms_incoming_msg_info *incoming_msg; + pdu = string2data(args->pdu); + if (pdu == NULL) { + free(args->pdu); - ril_data.state.sms_incoming_msg_tpid = 0; + if (args->smsc != NULL) + free(args->smsc); - incoming_msg = ipc_sms_incoming_msg_info_find(); - if (incoming_msg == NULL) - return; + goto error; + } - ipc_sms_incoming_msg_complete(incoming_msg->pdu, incoming_msg->length, incoming_msg->type, incoming_msg->tpid); - ipc_sms_incoming_msg_unregister(incoming_msg); -} + free(args->pdu); -void ipc_sms_incoming_msg_complete(char *pdu, int length, unsigned char type, unsigned char tpid) -{ - if (pdu == NULL || length <= 0) - return; + if (args->smsc == NULL) + goto setup; - ril_data.state.sms_incoming_msg_tpid = tpid; + smsc_size = string2data_size(args->smsc); + if (smsc_size == 0) { + free(args->smsc); - if (type == IPC_SMS_TYPE_POINT_TO_POINT) { - ril_request_unsolicited(RIL_UNSOL_RESPONSE_NEW_SMS, pdu, length); - } else if (type == IPC_SMS_TYPE_STATUS_REPORT) { - ril_request_unsolicited(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, pdu, length); - } else { - RIL_LOGE("Unhandled message type: %x", type); + goto error; } - free(pdu); -} - -void ipc_sms_incoming_msg(struct ipc_message_info *info) -{ - struct ipc_sms_incoming_msg *msg; - unsigned char *pdu_hex; - char *pdu; - int length; - int rc; + smsc = string2data(args->smsc); + if (smsc == NULL) { + free(args->smsc); - if (info->data == NULL || info->length < sizeof(struct ipc_sms_incoming_msg)) goto error; - - msg = (struct ipc_sms_incoming_msg *) info->data; - pdu_hex = ((unsigned char *) info->data + sizeof(struct ipc_sms_incoming_msg)); - - length = msg->length * 2 + 1; - pdu = (char *) calloc(1, length); - - bin2hex(pdu_hex, msg->length, pdu); - - if (ril_data.state.sms_incoming_msg_tpid != 0) { - RIL_LOGD("Another message is waiting ACK, queuing"); - rc = ipc_sms_incoming_msg_register(pdu, length, msg->type, msg->msg_tpid); - if (rc < 0) - RIL_LOGE("Unable to register incoming msg"); - - return; } - ipc_sms_incoming_msg_complete(pdu, length, msg->type, msg->msg_tpid); - - return; - -error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_sms_acknowledge(RIL_Token t, void *data, size_t length) -{ - struct ipc_sms_deliver_report_request report_msg; - int success, fail_cause; + free(args->smsc); - if (data == NULL || length < 2 * sizeof(int)) +setup: + request_size = ipc_sms_save_msg_size_setup(&request_header, smsc, smsc_size, pdu, pdu_size); + if (request_size == 0) goto error; - if (ril_data.state.sms_incoming_msg_tpid == ril_data.state.ril_sms_tpid) { - ril_data.state.ril_sms_tpid = 0; - - ril_request_complete(t, RIL_E_SUCCESS, NULL, 0); - - ipc_sms_incoming_msg_next(); - - return; - } - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; + request_data = ipc_sms_save_msg_setup(&request_header, smsc, smsc_size, pdu, pdu_size); + if (request_data == NULL) + goto error; - success = ((int *) data)[0]; - fail_cause = ((int *) data)[1]; + rc = ipc_gen_phone_res_expect_abort(ipc_fmt_request_seq(token), IPC_SMS_SAVE_MSG); + if (rc < 0) + goto error; - if (ril_data.state.sms_incoming_msg_tpid == 0) { - RIL_LOGE("There is no SMS message to ACK!"); + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SMS_SAVE_MSG, IPC_TYPE_EXEC, request_data, request_size); + if (rc < 0) goto error; - } - report_msg.type = IPC_SMS_TYPE_STATUS_REPORT; - report_msg.error = ril2ipc_sms_ack_error(success, fail_cause); - report_msg.msg_tpid = ril_data.state.sms_incoming_msg_tpid; - report_msg.unk = 0; + rc = RIL_REQUEST_HANDLED; + goto complete; - ipc_gen_phone_res_expect_to_abort(ril_request_get_id(t), IPC_SMS_DELIVER_REPORT); +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); - ipc_fmt_send(IPC_SMS_DELIVER_REPORT, IPC_TYPE_EXEC, (void *) &report_msg, sizeof(report_msg), ril_request_get_id(t)); + rc = RIL_REQUEST_COMPLETED; - ipc_sms_incoming_msg_next(); +complete: + if (smsc != NULL && smsc_size > 0) + free(smsc); - return; + if (pdu != NULL && pdu_size > 0) + free(pdu); -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); + if (request_data != NULL && request_size > 0) + free(request_data); - ipc_sms_incoming_msg_next(); + return rc; } -void ipc_sms_deliver_report(struct ipc_message_info *info) +int ipc_sms_del_msg(struct ipc_message *message) { - struct ipc_sms_deliver_report_response *report_msg; - RIL_Errno e; - int error_code; + struct ipc_sms_del_msg_response_data *data; - if (info->data == NULL || info->length < sizeof(struct ipc_sms_deliver_report_response)) - goto error; + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sms_del_msg_response_data)) + return -1; - report_msg = (struct ipc_sms_deliver_report_response *) info->data; - e = ipc2ril_sms_ack_error(report_msg->error, &error_code); + if (!ipc_seq_valid(message->aseq)) + return 0; - ril_request_complete(ril_request_get_token(info->aseq), e, NULL, 0); + data = (struct ipc_sms_del_msg_response_data *) message->data; - return; + if (data->error) + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + else + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); -error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return 0; } -void ril_request_write_sms_to_sim(RIL_Token token, void *data, size_t size) +int ril_request_delete_sms_on_sim(void *data, size_t size, RIL_Token token) { - struct ipc_sms_save_msg_request_data *sms_save_msg_request_data; - RIL_SMS_WriteArgs *args; - void *buffer = NULL; - size_t length; - size_t data_length; - size_t pdu_length = 0; - size_t pdu_hex_length = 0; - size_t smsc_length = 0; - size_t smsc_hex_length = 0; - unsigned char *p; + struct ipc_sms_del_msg_request_data request_data; + int index; + int rc; - if (data == NULL || size < sizeof(RIL_SMS_WriteArgs)) + if (data == NULL || size < sizeof(int)) goto error; - if (ril_radio_state_complete(RADIO_STATE_OFF, token)) - return; - - args = (RIL_SMS_WriteArgs *) data; - - if (args->pdu != NULL) { - pdu_length = strlen(args->pdu); - pdu_hex_length = pdu_length % 2 == 0 ? pdu_length / 2 : (pdu_length ^ 1) / 2; - } - - if (args->smsc != NULL) { - smsc_length = strlen(args->smsc); - smsc_hex_length = smsc_length % 2 == 0 ? smsc_length / 2 : (smsc_length ^ 1) / 2; - } - - data_length = pdu_hex_length + smsc_hex_length; - if (data_length == 0 || data_length > 0xff) + index = *((int *) data); + if (index == 0) goto error; - length = sizeof(struct ipc_sms_save_msg_request_data) + data_length; - buffer = malloc(length); - - sms_save_msg_request_data = (struct ipc_sms_save_msg_request_data *) buffer; - - memset(sms_save_msg_request_data, 0, sizeof(struct ipc_sms_save_msg_request_data)); - sms_save_msg_request_data->unknown = 0x02; - sms_save_msg_request_data->index = 12 - 1; - sms_save_msg_request_data->status = ril2ipc_sms_save_msg_status(args->status); - sms_save_msg_request_data->length = (unsigned char) (data_length & 0xff); - - p = (unsigned char *) buffer + sizeof(struct ipc_sms_save_msg_request_data); - - if (args->smsc != NULL && smsc_length > 0) { - hex2bin(args->smsc, smsc_length, p); - p += smsc_hex_length; - } - - if (args->pdu != NULL && pdu_length > 0) { - hex2bin(args->pdu, pdu_length, p); - p += pdu_hex_length; - } + rc = ipc_sms_del_msg_setup(&request_data, (unsigned short) (index - 1)); + if (rc < 0) + goto error; - ipc_gen_phone_res_expect_to_abort(ril_request_get_id(token), IPC_SMS_SAVE_MSG); + rc = ipc_gen_phone_res_expect_abort(ipc_fmt_request_seq(token), IPC_SMS_DEL_MSG); + if (rc < 0) + goto error; - ipc_fmt_send(IPC_SMS_SAVE_MSG, IPC_TYPE_EXEC, buffer, length, ril_request_get_id(token)); + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SMS_DEL_MSG, IPC_TYPE_EXEC, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + 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 (buffer != NULL) - free(buffer); + return rc; } -void ipc_sms_save_msg(struct ipc_message_info *info) +int ipc_sms_deliver_report(struct ipc_message *message) { - struct ipc_sms_save_msg_response_data *sms_save_msg_response_data; + struct ipc_sms_deliver_report_response_data *data; + RIL_Errno error; - if (info == NULL || info->data == NULL || info->length < sizeof(struct ipc_sms_save_msg_response_data)) - return; + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sms_deliver_report_response_data)) + return -1; - sms_save_msg_response_data = (struct ipc_sms_save_msg_response_data *) info->data; + if (!ipc_seq_valid(message->aseq)) + return 0; - if (sms_save_msg_response_data->error) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - else - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, NULL, 0); + data = (struct ipc_sms_deliver_report_response_data *) message->data; + + error = ipc2ril_sms_ack_error(data->ack); + + ril_request_complete(ipc_fmt_request_token(message->aseq), error, NULL, 0); + + return 0; } -void ril_request_delete_sms_on_sim(RIL_Token token, void *data, size_t size) +int ril_request_sms_acknowledge(void *data, size_t size, RIL_Token token) { - struct ipc_sms_del_msg_request_data sms_del_msg_request_data; - int index = 0; + struct ipc_sms_deliver_report_request_data report_data; + void *id_data; + size_t id_size; + unsigned char id; + int *values; + int rc; - if (data == NULL || size < sizeof(index)) + if (data == NULL || size < 2 * sizeof(int)) goto error; - if (ril_radio_state_complete(RADIO_STATE_OFF, token)) - return; + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - index = *((int *) data); + values = (int *) data; - if (index <= 0 || index > 0xffff) + id_size = ril_request_data_size_get(RIL_REQUEST_SMS_ACKNOWLEDGE); + id_data = ril_request_data_get(RIL_REQUEST_SMS_ACKNOWLEDGE); + + if (id_data == NULL || id_size == 0) { + RIL_LOGE("%s: No SMS left to acknowledge", __func__); goto error; + } - memset(&sms_del_msg_request_data, 0, sizeof(sms_del_msg_request_data)); - sms_del_msg_request_data.unknown = 0x02; - sms_del_msg_request_data.index = (short) index - 1; + id = *((unsigned char *) id_data); - ipc_gen_phone_res_expect_to_abort(ril_request_get_id(token), IPC_SMS_DEL_MSG); + free(id_data); - ipc_fmt_send(IPC_SMS_DEL_MSG, IPC_TYPE_EXEC, (unsigned char *) &sms_del_msg_request_data, sizeof(sms_del_msg_request_data), ril_request_get_id(token)); + memset(&report_data, 0, sizeof(report_data)); + report_data.type = IPC_SMS_TYPE_STATUS_REPORT; + report_data.ack = ril2ipc_sms_ack(values[0], values[1]); + report_data.id = id; - return; + rc = ipc_gen_phone_res_expect_abort(ipc_fmt_request_seq(token), IPC_SMS_DELIVER_REPORT); + if (rc < 0) + goto error; -error: - ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); -} + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SMS_DELIVER_REPORT, IPC_TYPE_EXEC, (void *) &report_data, sizeof(report_data)); + if (rc < 0) + goto error; -void ipc_sms_del_msg(struct ipc_message_info *info) -{ - struct ipc_sms_del_msg_response_data *sms_del_msg_response_data; + rc = RIL_REQUEST_HANDLED; + goto complete; - if (info == NULL || info->data == NULL || info->length < sizeof(struct ipc_sms_del_msg_response_data)) - return; +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); - sms_del_msg_response_data = (struct ipc_sms_del_msg_response_data *) info->data; + rc = RIL_REQUEST_COMPLETED; - if (sms_del_msg_response_data->error) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - else - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, NULL, 0); +complete: + return rc; } -/* - * RIL SMS - */ - -int ril_sms_send(char *number, char *message) +int ipc_sms_svc_center_addr(struct ipc_message *message) { - char *pdu; - size_t length; + struct ipc_sms_svc_center_addr_header *header; + void *smsc = NULL; + size_t smsc_size = 0; + void *pdu = NULL; + size_t pdu_size = 0; int rc; - pdu = pdu_create(number, message); - if (pdu == NULL) + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sms_svc_center_addr_header)) return -1; - length = strlen(pdu); - if (length == 0) - return -1; + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; - ril_data.state.ril_sms_tpid = RIL_SMS_TPID; + header = (struct ipc_sms_svc_center_addr_header *) message->data; + if (header->length == 0 || header->length > (message->size - sizeof(struct ipc_sms_svc_center_addr_header))) + goto error; - if (ril_data.state.sms_incoming_msg_tpid != 0) { - RIL_LOGD("Another message is waiting ACK, queuing"); - rc = ipc_sms_incoming_msg_register(pdu, length, IPC_SMS_TYPE_POINT_TO_POINT, ril_data.state.ril_sms_tpid); - if (rc < 0) { - RIL_LOGE("Unable to register incoming msg"); - return -1; - } + pdu_size = ril_request_data_size_get(RIL_REQUEST_SEND_SMS); + if (pdu_size == 0) + goto error; - return 0; - } + pdu = ril_request_data_get(RIL_REQUEST_SEND_SMS); + if (pdu == NULL) + goto error; - ipc_sms_incoming_msg_complete(pdu, length, IPC_SMS_TYPE_POINT_TO_POINT, ril_data.state.ril_sms_tpid); + smsc_size = ipc_sms_svc_center_addr_smsc_size_extract(message->data, message->size); + if (smsc_size == 0) + goto error; - return 0; -} + smsc = ipc_sms_svc_center_addr_smsc_extract(message->data, message->size); + if (smsc == NULL) + goto error; -/* - * Apparently non-SMS-messages-related function - */ + rc = ril_request_send_sms_complete(message->aseq, smsc, smsc_size, pdu, pdu_size); + if (rc < 0) + goto error; -void ipc_sms_device_ready(struct ipc_message_info *info) -{ -#if RIL_VERSION >= 7 - if (ril_data.state.radio_state == RADIO_STATE_ON) { -#else - if (ril_data.state.radio_state == RADIO_STATE_SIM_READY) { -#endif - ipc_fmt_send(IPC_SMS_DEVICE_READY, IPC_TYPE_SET, NULL, 0, info->aseq); - } + goto complete; - ril_tokens_check(); +error: + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SMS_SEND_FAIL_RETRY, NULL, 0); + +complete: + if (pdu != NULL) + free(pdu); + + return 0; } @@ -1,132 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#define LOG_TAG "RIL-SND" -#include <utils/Log.h> - -#include "samsung-ril.h" -#include "util.h" - -unsigned char srs2ipc_call_type(int type) -{ - switch (type) { - case SRS_SND_TYPE_VOICE: - return IPC_SND_VOLUME_TYPE_VOICE; - case SRS_SND_TYPE_SPEAKER: - return IPC_SND_VOLUME_TYPE_SPEAKER; - case SRS_SND_TYPE_HEADSET: - return IPC_SND_VOLUME_TYPE_HEADSET; - case SRS_SND_TYPE_BTVOICE: - return IPC_SND_VOLUME_TYPE_BTVOICE; - default: - RIL_LOGE("Unknown call type: 0x%x", type); - return 0; - } -} - -unsigned char srs2ipc_audio_path(int path) -{ - switch (path) { - case SRS_SND_PATH_HANDSET: - return IPC_SND_AUDIO_PATH_HANDSET; - case SRS_SND_PATH_HEADSET: - return IPC_SND_AUDIO_PATH_HEADSET; - case SRS_SND_PATH_SPEAKER: - return IPC_SND_AUDIO_PATH_SPEAKER; - case SRS_SND_PATH_BLUETOOTH: - return IPC_SND_AUDIO_PATH_BLUETOOTH; - case SRS_SND_PATH_BLUETOOTH_NO_NR: - return IPC_SND_AUDIO_PATH_BLUETOOTH_NO_NR; - case SRS_SND_PATH_HEADPHONE: - return IPC_SND_AUDIO_PATH_HEADPHONE; - default: - RIL_LOGE("Unknown audio path: 0x%x", path); - return 0; - } -} - -void ril_request_set_mute(RIL_Token t, void *data, int length) -{ - int *value; - unsigned char mute; - - if (data == NULL || length < (int) sizeof(int)) - return; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - value = (int *) data; - mute = *value ? 1 : 0; - - RIL_LOGD("Mute is %d\n", mute); - - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_SND_MIC_MUTE_CTRL); - - ipc_fmt_send(IPC_SND_MIC_MUTE_CTRL, IPC_TYPE_SET, (void *) &mute, sizeof(mute), ril_request_get_id(t)); -} - -void srs_snd_set_call_clock_sync(struct srs_message *message) -{ - unsigned char *sync; - - if (message == NULL || message->data == NULL || message->length < (int) sizeof(unsigned char)) - return; - - sync = (unsigned char *) message->data; - - RIL_LOGD("Clock sync is 0x%x\n", *sync); - - ipc_fmt_send(IPC_SND_CLOCK_CTRL, IPC_TYPE_EXEC, sync, sizeof(unsigned char), ril_request_id_get()); -} - -void srs_snd_set_call_volume(struct srs_message *message) -{ - struct srs_snd_call_volume *call_volume; - struct ipc_snd_spkr_volume_ctrl volume_ctrl; - - if (message == NULL || message->data == NULL || message->length < (int) sizeof(struct srs_snd_call_volume)) - return; - - call_volume = (struct srs_snd_call_volume *) message->data; - - RIL_LOGD("Call volume for: 0x%x vol = 0x%x\n", call_volume->type, call_volume->volume); - - memset(&volume_ctrl, 0, sizeof(volume_ctrl)); - volume_ctrl.type = srs2ipc_call_type(call_volume->type); - volume_ctrl.volume = call_volume->volume; - - ipc_fmt_send(IPC_SND_SPKR_VOLUME_CTRL, IPC_TYPE_SET, (void *) &volume_ctrl, sizeof(volume_ctrl), ril_request_id_get()); -} - -void srs_snd_set_call_audio_path(struct srs_message *message) -{ - int *audio_path; - unsigned char path; - - if (message == NULL || message->data == NULL || message->length < (int) sizeof(int)) - return; - - audio_path = (int *) message->data; - path = srs2ipc_audio_path(*audio_path); - - RIL_LOGD("Audio path to: 0x%x\n", path); - - ipc_fmt_send(IPC_SND_AUDIO_PATH_CTRL, IPC_TYPE_SET, (void *) &path, sizeof(path), ril_request_id_get()); -} @@ -0,0 +1,159 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> + * + * Samsung-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. + * + * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> + +#define LOG_TAG "RIL" +#include <utils/Log.h> + +#include <samsung-ril.h> + +unsigned char srs2ipc_call_type(int type) +{ + switch (type) { + case SRS_SND_TYPE_VOICE: + return IPC_SND_VOLUME_TYPE_VOICE; + case SRS_SND_TYPE_SPEAKER: + return IPC_SND_VOLUME_TYPE_SPEAKER; + case SRS_SND_TYPE_HEADSET: + return IPC_SND_VOLUME_TYPE_HEADSET; + case SRS_SND_TYPE_BTVOICE: + return IPC_SND_VOLUME_TYPE_BTVOICE; + default: + return IPC_SND_VOLUME_TYPE_VOICE; + } +} + +unsigned char srs2ipc_audio_path(int path) +{ + switch (path) { + case SRS_SND_PATH_HANDSET: + return IPC_SND_AUDIO_PATH_HANDSET; + case SRS_SND_PATH_HEADSET: + return IPC_SND_AUDIO_PATH_HEADSET; + case SRS_SND_PATH_SPEAKER: + return IPC_SND_AUDIO_PATH_SPEAKER; + case SRS_SND_PATH_BLUETOOTH: + return IPC_SND_AUDIO_PATH_BLUETOOTH; + case SRS_SND_PATH_BLUETOOTH_NO_NR: + return IPC_SND_AUDIO_PATH_BLUETOOTH_NO_NR; + case SRS_SND_PATH_HEADPHONE: + return IPC_SND_AUDIO_PATH_HEADPHONE; + default: + return IPC_SND_AUDIO_PATH_HANDSET; + } +} + +int srs_snd_set_call_volume(struct srs_message *message) +{ + struct ipc_snd_spkr_volume_ctrl_data request_data; + struct srs_snd_call_volume_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct srs_snd_call_volume_data)) + return -1; + + data = (struct srs_snd_call_volume_data *) message->data; + + memset(&request_data, 0, sizeof(request_data)); + request_data.type = srs2ipc_call_type(data->type); + request_data.volume = data->volume; + + rc = ipc_fmt_send(ipc_fmt_seq(), IPC_SND_SPKR_VOLUME_CTRL, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + return 0; + + return 0; +} + +int ril_request_set_mute(void *data, size_t size, RIL_Token token) +{ + struct ipc_snd_mic_mute_ctrl_data request_data; + int mute; + int rc; + + if (data == NULL || size < sizeof(int)) + goto error; + + mute = *((int *) data); + + memset(&request_data, 0, sizeof(request_data)); + request_data.mute = !!mute; + + rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_SND_MIC_MUTE_CTRL); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SND_MIC_MUTE_CTRL, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int srs_snd_set_call_audio_path(struct srs_message *message) +{ + struct ipc_snd_audio_path_ctrl_data request_data; + struct srs_snd_call_audio_path_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct srs_snd_call_audio_path_data)) + return -1; + + data = (struct srs_snd_call_audio_path_data *) message->data; + + memset(&request_data, 0, sizeof(request_data)); + request_data.path = srs2ipc_audio_path(data->path); + + rc = ipc_fmt_send(ipc_fmt_seq(), IPC_SND_AUDIO_PATH_CTRL, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + return 0; + + return 0; +} + +int srs_snd_set_call_clock_sync(struct srs_message *message) +{ + struct ipc_snd_clock_ctrl_data request_data; + struct srs_snd_call_clock_sync_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct srs_snd_call_clock_sync_data)) + return -1; + + data = (struct srs_snd_call_clock_sync_data *) message->data; + + memset(&request_data, 0, sizeof(request_data)); + request_data.sync = data->sync; + + rc = ipc_fmt_send(ipc_fmt_seq(), IPC_SND_CLOCK_CTRL, IPC_TYPE_EXEC, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + return 0; + + return 0; +} diff --git a/srs-client/include/srs-client.h b/srs-client/include/srs-client.h index 632e882..16eee49 100644 --- a/srs-client/include/srs-client.h +++ b/srs-client/include/srs-client.h @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2013 Paul Kocialkowski <contact@oaulk.fr> + * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,43 +17,46 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ -#include <pthread.h> - -#include <samsung-ril-socket.h> - #ifndef _SRS_CLIENT_H_ #define _SRS_CLIENT_H_ -#define SRS_CLIENT_TIMEOUT 500000 +#include <stdlib.h> +#include <pthread.h> -#define SRS_CLIENT_LOCK(client) pthread_mutex_lock(&(client->mutex)) -#define SRS_CLIENT_UNLOCK(client) pthread_mutex_unlock(&(client->mutex)) +#include <samsung-ril-socket.h> -typedef void (*srs_client_thread_cb)(struct srs_message *message); +#define SRS_CLIENT_LOCK(client) pthread_mutex_lock(&client->mutex) +#define SRS_CLIENT_UNLOCK(client) pthread_mutex_unlock(&client->mutex) struct srs_client { int fd; + int event_fd; pthread_mutex_t mutex; pthread_t thread; - int thread_run; - srs_client_thread_cb thread_cb; + void (*callback)(struct srs_client *client, struct srs_message *message); }; -int srs_client_recv_message(struct srs_client *client, struct srs_message *message); -int srs_client_send_message(struct srs_client *client, struct srs_message *message); -int srs_client_send(struct srs_client *client, unsigned short command, void *data, int length); +const char *srs_command_string(unsigned short command); +int srs_header_setup(struct srs_header *header, + const struct srs_message *message); +int srs_message_setup(const struct srs_header *header, + struct srs_message *message); +int srs_ping(struct srs_client *client); + +struct srs_client *srs_client_create(void); +int srs_client_destroy(struct srs_client *client); int srs_client_open(struct srs_client *client); int srs_client_close(struct srs_client *client); -int srs_client_create(struct srs_client **client_p); -int srs_client_destroy(struct srs_client *client); - -int srs_client_thread_start(struct srs_client *client, - srs_client_thread_cb cb); -int srs_client_thread_stop(struct srs_client *client); - -int srs_client_ping(struct srs_client *client); +int srs_client_poll(struct srs_client *client); +int srs_client_send(struct srs_client *client, unsigned short command, + void *data, size_t size); +int srs_client_recv(struct srs_client *client, struct srs_message *message); +int srs_client_loop(struct srs_client *client); +int srs_client_loop_start(struct srs_client *client, + void (*callback)(struct srs_client *client, struct srs_message *message)); +int srs_client_loop_stop(struct srs_client *client); #endif diff --git a/srs-client/srs-client.c b/srs-client/srs-client.c index 109b607..2e1c75d 100644 --- a/srs-client/srs-client.c +++ b/srs-client/srs-client.c @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2013 Paul Kocialkowski <contact@oaulk.fr> + * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ #include <sys/socket.h> #include <sys/un.h> #include <sys/select.h> +#include <sys/eventfd.h> #include <signal.h> #include <arpa/inet.h> @@ -39,120 +40,254 @@ #include <srs-client.h> /* - * SRS Client fops + * Utils */ -int srs_client_recv_message(struct srs_client *client, struct srs_message *message) +const char *srs_command_string(unsigned short command) { - struct srs_header *header_p; - struct srs_header header; - void *data = NULL; - int length = 0; + static char command_string[7] = { 0 }; + + switch (command) { + case SRS_CONTROL_PING: + return "SRS_CONTROL_PING"; + case SRS_SND_SET_CALL_VOLUME: + return "SRS_SND_SET_CALL_VOLUME"; + case SRS_SND_SET_CALL_AUDIO_PATH: + return "SRS_SND_SET_CALL_AUDIO_PATH"; + case SRS_SND_SET_CALL_CLOCK_SYNC: + return "SRS_SND_SET_CALL_CLOCK_SYNC"; + default: + snprintf((char *) &command_string, sizeof(command_string), "0x%04x", command); + return command_string; + } +} - struct timeval timeout; - fd_set fds; - int rc; +int srs_header_setup(struct srs_header *header, + const struct srs_message *message) +{ + if (header == NULL || message == NULL) + return -1; - if (client == NULL || message == NULL || client->fd < 0) - return -EINVAL; + memset(header, 0, sizeof(struct srs_header)); + header->length = message->size + sizeof(struct srs_header); + header->group = SRS_GROUP(message->command); + header->index = SRS_INDEX(message->command); + + return 0; +} + +int srs_message_setup(const struct srs_header *header, + struct srs_message *message) +{ + if (header == NULL || message == NULL) + return -1; memset(message, 0, sizeof(struct srs_message)); - memset(&header, 0, sizeof(header)); + message->command = SRS_COMMAND(header->group, header->index); + message->data = NULL; + message->size = 0; - timeout.tv_sec = (SRS_CLIENT_TIMEOUT - SRS_CLIENT_TIMEOUT % 1000000) / 1000000; - timeout.tv_usec = SRS_CLIENT_TIMEOUT % 1000000; + return 0; +} - FD_ZERO(&fds); - FD_SET(client->fd, &fds); +/* + * SRS + */ - rc = select(client->fd + 1, &fds, NULL, NULL, &timeout); - if (rc == 0) { - rc = 0; - goto done; - } else if (rc < 0 || !FD_ISSET(client->fd, &fds)) +int srs_ping(struct srs_client *client) +{ + struct srs_message message; + struct srs_control_ping_data ping; + struct srs_control_ping_data *pong; + int rc; + + if (client == NULL) + return -1; + + memset(&message, 0, sizeof(message)); + + memset(&ping, 0, sizeof(ping)); + ping.caffe = SRS_CONTROL_CAFFE; + + rc = srs_client_send(client, SRS_CONTROL_PING, &ping, sizeof(ping)); + if (rc < 0) goto error; - SRS_CLIENT_LOCK(client); - rc = read(client->fd, &header, sizeof(header)); - SRS_CLIENT_UNLOCK(client); + rc = srs_client_poll(client); + if (rc <= 0) + goto error; - if (rc != sizeof(header)) + rc = srs_client_recv(client, &message); + if (rc < 0 || message.data == NULL || message.size < sizeof(struct srs_control_ping_data)) goto error; - header_p = &header; - message->command = SRS_COMMAND(header_p); + pong = (struct srs_control_ping_data *) message.data; + if (pong->caffe != SRS_CONTROL_CAFFE) + goto error; - length = header.length - sizeof(header); - if (length > 0) { - data = calloc(1, length); - if (data == NULL) - goto error; + rc = 0; + goto complete; - FD_ZERO(&fds); - FD_SET(client->fd, &fds); +error: + rc = -1; + +complete: + if (message.data != NULL && message.size > 0) + free(message.data); + + return rc; +} - rc = select(client->fd + 1, &fds, NULL, NULL, &timeout); - if (rc <= 0 || !FD_ISSET(client->fd, &fds)) - goto error; +/* + * SRS client + */ + +struct srs_client *srs_client_create(void) +{ + struct srs_client *client; + + signal(SIGPIPE, SIG_IGN); - SRS_CLIENT_LOCK(client); - rc = read(client->fd, data, length); - SRS_CLIENT_UNLOCK(client); + client = (struct srs_client *) calloc(1, sizeof(struct srs_client)); + client->fd = -1; + client->event_fd = -1; - if (rc != length) - goto error; + pthread_mutex_init(&client->mutex, NULL); - message->data = data; - message->length = length; - } + return client; +} + +int srs_client_destroy(struct srs_client *client) +{ + if (client == NULL) + return -1; - rc = header.length; - goto done; + pthread_mutex_destroy(&client->mutex); + + memset(client, 0, sizeof(struct srs_client)); + free(client); + + return 0; +} + +int srs_client_open(struct srs_client *client) +{ + int flags; + int fd = 0; + int i = 0; + int rc; + + if (client == NULL) + return -1; + + SRS_CLIENT_LOCK(client); + + do { + if (fd < 0) + usleep(50000); + +#if RIL_VERSION >= 6 + fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); +#else + fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); +#endif + + flags = fcntl(fd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(fd, F_SETFL, flags); + + i++; + } while (fd < 0 && i < 5); + + if (fd < 0) + goto error; + + client->fd = fd; + + rc = 0; + goto complete; error: rc = -1; - if (data != NULL) - free(data); +complete: + SRS_CLIENT_UNLOCK(client); -done: return rc; } -int srs_client_send_message(struct srs_client *client, struct srs_message *message) +int srs_client_close(struct srs_client *client) { - struct srs_header header; - unsigned char *p = NULL; - void *data = NULL; - int length = 0; + if (client == NULL ) + return -1; + + SRS_CLIENT_LOCK(client); + + if (client->fd >= 0) { + close(client->fd); + client->fd = -1; + } + + SRS_CLIENT_UNLOCK(client); + + return 0; +} + +int srs_client_poll(struct srs_client *client) +{ + struct timeval timeout; + fd_set fds; + int rc; + + if (client == NULL || client->fd < 0) + return -1; + + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 50000; + FD_ZERO(&fds); + FD_SET(client->fd, &fds); + + rc = select(client->fd + 1, &fds, NULL, NULL, &timeout); + + return rc; +} + +int srs_client_send(struct srs_client *client, unsigned short command, + void *data, size_t size) +{ + struct srs_message message; + struct srs_header header; + void *buffer = NULL; + size_t length; struct timeval timeout; fd_set fds; + unsigned char *p; int rc; - if (client == NULL || message == NULL || client->fd < 0) - return -EINVAL; + if (client == NULL || client->fd < 0) + return -1; + + SRS_CLIENT_LOCK(client); + + memset(&message, 0, sizeof(message)); + message.command = command; + message.data = data; + message.size = size; - memset(&header, 0, sizeof(header)); - header.length = message->length + sizeof(header); - header.group = SRS_GROUP(message->command); - header.index = SRS_INDEX(message->command); + srs_header_setup(&header, &message); length = header.length; - data = calloc(1, length); - if (data == NULL) - goto error; + buffer = calloc(1, length); - p = (unsigned char *) data; - memcpy(p, &header, sizeof(header)); - p += sizeof(header); - if (message->data != NULL && message->length > 0) { - memcpy(p, message->data, message->length); - p += message->length; + memcpy(buffer, &header, sizeof(header)); + if (message.data != NULL && message.size > 0) { + p = (unsigned char *) buffer + sizeof(header); + memcpy(p, message.data, message.size); } - timeout.tv_sec = (SRS_CLIENT_TIMEOUT - SRS_CLIENT_TIMEOUT % 1000000) / 1000000; - timeout.tv_usec = SRS_CLIENT_TIMEOUT % 1000000; + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 300; FD_ZERO(&fds); FD_SET(client->fd, &fds); @@ -161,204 +296,224 @@ int srs_client_send_message(struct srs_client *client, struct srs_message *messa if (rc <= 0 || !FD_ISSET(client->fd, &fds)) goto error; - SRS_CLIENT_LOCK(client); - rc = write(client->fd, data, length); - SRS_CLIENT_UNLOCK(client); - - if (rc != length) + rc = write(client->fd, buffer, length); + if (rc < (int) length) goto error; - rc = length; - goto done; + rc = 0; + goto complete; error: rc = -1; -done: - if (data != NULL) - free(data); +complete: + if (buffer != NULL) + free(buffer); + + SRS_CLIENT_UNLOCK(client); return rc; } -int srs_client_send(struct srs_client *client, unsigned short command, void *data, int length) +int srs_client_recv(struct srs_client *client, struct srs_message *message) { - struct srs_message message; + struct srs_header *header; + void *buffer = NULL; + size_t length; + struct timeval timeout; + fd_set fds; + unsigned char *p; + int rc; - memset(&message, 0, sizeof(message)); - message.command = command; - message.data = data; - message.length = length; + if (client == NULL || client->fd < 0 || message == NULL) + return -1; - return srs_client_send_message(client, &message); -} + SRS_CLIENT_LOCK(client); -int srs_client_open(struct srs_client *client) -{ - int fd; + length = SRS_BUFFER_LENGTH; + buffer= calloc(1, length); - if (client == NULL) - return -EINVAL; -#if RIL_VERSION >= 6 - fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); -#else - fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); -#endif - if (fd < 0) { - client->fd = -1; - return -1; - } + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 300; - client->fd = fd; - return 0; -} + FD_ZERO(&fds); + FD_SET(client->fd, &fds); -int srs_client_close(struct srs_client *client) -{ - if (client == NULL || client->fd < 0) - return -EINVAL; + rc = select(client->fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0 || !FD_ISSET(client->fd, &fds)) + goto error; - close(client->fd); - client->fd = -1; + rc = read(client->fd, buffer, length); + if (rc < (int) sizeof(struct srs_header)) + goto error; - return 0; -} + header = (struct srs_header *) buffer; -int srs_client_create(struct srs_client **client_p) -{ - struct srs_client *client; + srs_message_setup(header, message); - if (client_p == NULL) - return -EINVAL; + length = header->length - sizeof(struct srs_header); + if (length > 0) { + message->size = length; + message->data = calloc(1, length); - client = calloc(1, sizeof(struct srs_client)); - if (client == NULL) { - *client_p = NULL; - return -1; + p = (unsigned char *) buffer + sizeof(struct srs_header); + memcpy(message->data, p, length); } - client->fd = -1; - pthread_mutex_init(&(client->mutex), NULL); + rc = 0; + goto complete; + +error: + rc = -1; - *client_p = client; +complete: + if (buffer != NULL) + free(buffer); - return 0; + SRS_CLIENT_UNLOCK(client); + + return rc; } -int srs_client_destroy(struct srs_client *client) +int srs_client_loop(struct srs_client *client) { - if (client == NULL) - return -EINVAL; + struct srs_message message; + unsigned long int event; + fd_set fds; + int fd_max; + int rc; - pthread_mutex_destroy(&(client->mutex)); + if (client == NULL || client->callback == NULL) + return -1; - free(client); + while (1) { + if (client->fd < 0 || client->event_fd < 0) + return -1; + + FD_ZERO(&fds); + FD_SET(client->fd, &fds); + FD_SET(client->event_fd, &fds); + + fd_max = client->fd > client->event_fd ? client->fd : client->event_fd; + + rc = select(fd_max + 1, &fds, NULL, NULL, NULL); + if (rc < 0) + return -1; + + if (FD_ISSET(client->event_fd, &fds)) { + read(client->event_fd, &event, sizeof(event)); + break; + } + + if (!FD_ISSET(client->fd, &fds)) + continue; + + memset(&message, 0, sizeof(struct srs_message)); + + rc = srs_client_recv(client, &message); + if (rc < 0) + return -1; + + client->callback(client, &message); + + if (message.data != NULL && message.size > 0) + free(message.data); + } return 0; } -/* - * SRS Client thread - */ - void *srs_client_thread(void *data) { - struct srs_message message; struct srs_client *client; - int rc; + int rc = 0; + int i = 0; if (data == NULL) return NULL; client = (struct srs_client *) data; - if (client->thread_cb == NULL) - goto done; + do { + if (rc < 0) { + rc = srs_client_close(client); + if (rc < 0) + break; - while (client->thread_run) { - rc = srs_client_recv_message(client, &message); - if (rc < 0) - goto done; + rc = srs_client_open(client); + if (rc < 0) + break; + } - client->thread_cb(&message); - } + rc = srs_client_loop(client); -done: - client->thread_run = 0; + i++; + } while (rc < 0 && i < 5); - return NULL; + return 0; } -int srs_client_thread_start(struct srs_client *client, - srs_client_thread_cb cb) +int srs_client_loop_start(struct srs_client *client, + void (*callback)(struct srs_client *client, struct srs_message *message)) { pthread_attr_t attr; + int event_fd = -1; int rc; - if (client == NULL || cb == NULL) - return -EINVAL; + if (client == NULL || callback == NULL) + return -1; + + SRS_CLIENT_LOCK(client); + + event_fd = eventfd(0, EFD_NONBLOCK); + if (event_fd < 0) + goto error; - client->thread_cb = cb; - client->thread_run = 1; + client->event_fd = event_fd; + client->callback = callback; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - rc = pthread_create(&(client->thread), &attr, srs_client_thread, (void *) client); + rc = pthread_create(&client->thread, &attr, srs_client_thread, (void *) client); if (rc != 0) - return -1; + goto error; - return 0; -} + rc = 0; + goto complete; -int srs_client_thread_stop(struct srs_client *client) -{ - if (client == NULL) - return -EINVAL; +error: + if (event_fd >= 0) { + close(event_fd); + client->event_fd = -1; + } - client->thread_run = 0; + rc = -1; - return 0; -} +complete: + SRS_CLIENT_UNLOCK(client); -/* - * SRS Client inline - */ + return rc; +} -int srs_client_ping(struct srs_client *client) +int srs_client_loop_stop(struct srs_client *client) { - struct srs_message message; - struct srs_control_ping ping; - struct srs_control_ping *ping_p; - int rc; + unsigned long int event; - if (client == NULL) + if (client == NULL || client->event_fd < 0) return -1; - memset(&message, 0, sizeof(message)); - - ping.caffe = SRS_CONTROL_CAFFE; - rc = srs_client_send(client, SRS_CONTROL_PING, &ping, sizeof(ping)); - if (rc < 0) - goto error; - - rc = srs_client_recv_message(client, &message); - if (rc < 0 || message.length <= 0 || message.data == NULL) - goto error; + SRS_CLIENT_LOCK(client); - ping_p = (struct srs_control_ping *) message.data; - if (ping_p->caffe != SRS_CONTROL_CAFFE) - goto error; + event = 1; + write(client->event_fd, &event, sizeof(event)); - rc = 0; - goto done; + SRS_CLIENT_UNLOCK(client); -error: - rc = -1; + pthread_join(client->thread, NULL); -done: - if (message.data != NULL) - free(message.data); + close(client->event_fd); + client->event_fd = -1; - return rc; + return 0; } @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,12 +17,15 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdlib.h> +#include <errno.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/select.h> +#include <sys/eventfd.h> #include <arpa/inet.h> #include <netinet/in.h> @@ -30,52 +33,213 @@ #define LOG_TAG "RIL-SRS" #include <utils/Log.h> +#include <hardware_legacy/power.h> -#include "samsung-ril.h" -#include "util.h" +#include <samsung-ril.h> +#include <utils.h> -int srs_client_register(struct srs_client_data *srs_client_data, int fd) +/* + * Utils + */ + +const char *srs_command_string(unsigned short command) +{ + static char command_string[7] = { 0 }; + + switch (command) { + case SRS_CONTROL_PING: + return "SRS_CONTROL_PING"; + case SRS_SND_SET_CALL_VOLUME: + return "SRS_SND_SET_CALL_VOLUME"; + case SRS_SND_SET_CALL_AUDIO_PATH: + return "SRS_SND_SET_CALL_AUDIO_PATH"; + case SRS_SND_SET_CALL_CLOCK_SYNC: + return "SRS_SND_SET_CALL_CLOCK_SYNC"; + default: + snprintf((char *) &command_string, sizeof(command_string), "0x%04x", command); + return command_string; + } +} + +void srs_log_send(struct ril_client *client, struct srs_message *message) { - struct srs_client_info *client; + if (client == NULL || message == NULL) + return; + + RIL_LOGD("\n"); + RIL_LOGD("%s: Sent %s message", __func__, client->name); + RIL_LOGD("%s: Message: command=%s, size=%d", __func__, srs_command_string(message->command), message->size); + if (message->size > 0) { + RIL_LOGD("=================================== %s data ===================================", client->name); + data_dump(message->data, message->size); + RIL_LOGD("================================================================================"); + } +} + +void srs_log_recv(struct ril_client *client, struct srs_message *message) +{ + if (client == NULL || message == NULL) + return; + + RIL_LOGD("\n"); + RIL_LOGD("%s: Received %s message", __func__, client->name); + RIL_LOGD("%s: Message: command=%s, size=%d", __func__, srs_command_string(message->command), message->size); + if (message->size > 0) { + RIL_LOGD("=================================== %s data ===================================", client->name); + data_dump(message->data, message->size); + RIL_LOGD("================================================================================"); + } +} + +int srs_header_setup(struct srs_header *header, + const struct srs_message *message) +{ + if (header == NULL || message == NULL) + return -1; + + memset(header, 0, sizeof(struct srs_header)); + header->length = message->size + sizeof(struct srs_header); + header->group = SRS_GROUP(message->command); + header->index = SRS_INDEX(message->command); + + return 0; +} + +int srs_message_setup(const struct srs_header *header, + struct srs_message *message) +{ + if (header == NULL || message == NULL) + return -1; + + memset(message, 0, sizeof(struct srs_message)); + message->command = SRS_COMMAND(header->group, header->index); + message->data = NULL; + message->size = 0; + + return 0; +} + +/* + * SRS + */ + +int srs_send(unsigned short command, const void *data, size_t size) +{ + struct ril_client *ril_client; + struct srs_data *srs_data; + struct srs_client *client; + struct srs_message message; + int rc; + + ril_client = ril_client_find_id(RIL_CLIENT_SRS); + if (ril_client == NULL || ril_client->data == NULL) + return -1; + + srs_data = (struct srs_data *) ril_client->data; + if (srs_data->event_fd < 0) + return -1; + + if (!ril_client->available) { + RIL_LOGE("%s client is not available", ril_client->name); + return -1; + } + + memset(&message, 0, sizeof(message)); + message.command = command; + message.data = (void *) data; + message.size = size; + + acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING); + + rc = srs_client_send(ril_client, &message); + if (rc < 0) { + RIL_LOGE("Sending to %s client failed", ril_client->name); + + release_wake_lock(RIL_VERSION_STRING); + + eventfd_send(srs_data->event_fd, SRS_CLIENT_IO_ERROR); + return -1; + } + + return 0; +} + +int srs_control_ping(struct srs_message *message) +{ + struct srs_control_ping_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct srs_control_ping_data)) + return -1; + + data = (struct srs_control_ping_data *) message->data; + if (data->caffe == SRS_CONTROL_CAFFE) { + rc = srs_send(SRS_CONTROL_PING, data, sizeof(struct srs_control_ping_data)); + if (rc < 0) { + RIL_LOGE("Sending SRS control ping failed"); + return 0; + } + } + + return 0; +} + +/* + * SRS client + */ + +int srs_client_register(struct ril_client *ril_client, int fd) +{ + struct srs_data *data; + struct srs_client *client; struct list_head *list_end; struct list_head *list; - if (srs_client_data == NULL) + if (ril_client == NULL || ril_client->data == NULL) return -1; - client = calloc(1, sizeof(struct srs_client_info)); - if (client == NULL) - return -1; + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); + client = calloc(1, sizeof(struct srs_client)); client->fd = fd; - list_end = srs_client_data->clients; + list_end = data->clients; while (list_end != NULL && list_end->next != NULL) list_end = list_end->next; - list = list_head_alloc((void *) client, list_end, NULL); + list = list_head_alloc(list_end, NULL, (void *) client); - if (srs_client_data->clients == NULL) - srs_client_data->clients = list; + if (data->clients == NULL) + data->clients = list; + + RIL_CLIENT_UNLOCK(ril_client); return 0; } -void srs_client_unregister(struct srs_client_data *srs_client_data, struct srs_client_info *client) +int srs_client_unregister(struct ril_client *ril_client, + struct srs_client *client) { + struct srs_data *data; struct list_head *list; - if (srs_client_data == NULL || client == NULL) - return; + if (ril_client == NULL || ril_client->data == NULL) + return -1; + + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); - list = srs_client_data->clients; + list = data->clients; while (list != NULL) { if (list->data == (void *) client) { - memset(client, 0, sizeof(struct srs_client_info)); + memset(client, 0, sizeof(struct srs_client)); free(client); - if (list == srs_client_data->clients) - srs_client_data->clients = list->next; + if (list == data->clients) + data->clients = list->next; list_head_free(list); @@ -84,497 +248,914 @@ void srs_client_unregister(struct srs_client_data *srs_client_data, struct srs_c list_continue: list = list->next; } + + RIL_CLIENT_UNLOCK(ril_client); + + return 0; } -struct srs_client_info *srs_client_info_find(struct srs_client_data *srs_client_data) +int srs_client_flush(struct ril_client *ril_client) { - struct srs_client_info *client; + struct srs_data *data; + struct srs_client *client; struct list_head *list; + struct list_head *list_next; + + if (ril_client == NULL || ril_client->data == NULL) + return -1; + + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); - list = srs_client_data->clients; + list = data->clients; while (list != NULL) { - client = (struct srs_client_info *) list->data; - if (client == NULL) + if (list->data != NULL) { + client = (struct srs_client *) list->data; + memset(client, 0, sizeof(struct srs_client)); + free(client); + } + + if (list == data->clients) + data->clients = list->next; + + list_next = list->next; + + list_head_free(list); + +list_continue: + list = list_next; + } + + RIL_CLIENT_UNLOCK(ril_client); + + return 0; +} + +struct srs_client *srs_client_find(struct ril_client *ril_client) +{ + struct srs_data *data; + struct srs_client *client; + struct list_head *list; + + if (ril_client == NULL || ril_client->data == NULL) + return NULL; + + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); + + list = data->clients; + while (list != NULL) { + if (list->data == NULL) goto list_continue; + client = (struct srs_client *) list->data; + + RIL_CLIENT_UNLOCK(ril_client); return client; list_continue: list = list->next; } + RIL_CLIENT_UNLOCK(ril_client); + return NULL; } -struct srs_client_info *srs_client_info_find_fd(struct srs_client_data *srs_client_data, int fd) +struct srs_client *srs_client_find_fd(struct ril_client *ril_client, int fd) { - struct srs_client_info *client; + struct srs_data *data; + struct srs_client *client; struct list_head *list; - list = srs_client_data->clients; + if (ril_client == NULL || ril_client->data == NULL) + return NULL; + + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); + + list = data->clients; while (list != NULL) { - client = (struct srs_client_info *) list->data; - if (client == NULL) + if (list->data == NULL) goto list_continue; - if (client->fd == fd) + client = (struct srs_client *) list->data; + + if (client->fd == fd) { + RIL_CLIENT_UNLOCK(ril_client); return client; + } list_continue: list = list->next; } + RIL_CLIENT_UNLOCK(ril_client); + return NULL; } -int srs_client_info_fill_fd_set(struct srs_client_data *srs_client_data, fd_set *fds) +struct srs_client *srs_client_find_fd_set(struct ril_client *ril_client, + fd_set *fds) { - struct srs_client_info *client; + struct srs_data *data; + struct srs_client *client; struct list_head *list; - int fd_max; - if (srs_client_data == NULL || fds == NULL) - return -1; + if (ril_client == NULL || ril_client->data == NULL || fds == NULL ) + return NULL; + + data = (struct srs_data *) ril_client->data; - fd_max = -1; - list = srs_client_data->clients; + RIL_CLIENT_LOCK(ril_client); + + list = data->clients; while (list != NULL) { - client = (struct srs_client_info *) list->data; - if (client == NULL) + if (list->data == NULL) goto list_continue; - FD_SET(client->fd, fds); - if (client->fd > fd_max) - fd_max = client->fd; + client = (struct srs_client *) list->data; + + if (FD_ISSET(client->fd, fds)) { + FD_CLR(client->fd, fds); + + RIL_CLIENT_UNLOCK(ril_client); + return client; + } list_continue: list = list->next; } - return fd_max; + RIL_CLIENT_UNLOCK(ril_client); + + return NULL; } -int srs_client_info_get_fd_set(struct srs_client_data *srs_client_data, fd_set *fds) +int srs_client_fd_set_setup(struct ril_client *ril_client, fd_set *fds) { - struct srs_client_info *client; + struct srs_data *data; + struct srs_client *client; struct list_head *list; - int fd; + int fd_max = -1; - if (srs_client_data == NULL || fds == NULL) + if (ril_client == NULL || ril_client->data == NULL || fds == NULL) return -1; - list = srs_client_data->clients; + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); + + FD_ZERO(fds); + + list = data->clients; while (list != NULL) { - client = (struct srs_client_info *) list->data; - if (client == NULL) + if (list->data == NULL) goto list_continue; - if (FD_ISSET(client->fd, fds)) { - FD_CLR(client->fd, fds); - return client->fd; - } + client = (struct srs_client *) list->data; + + FD_SET(client->fd, fds); + if (client->fd > fd_max) + fd_max = client->fd; list_continue: list = list->next; } - return -1; + RIL_CLIENT_UNLOCK(ril_client); + + return fd_max; } -int srs_client_send_message(struct srs_client_data *srs_client_data, struct srs_message *message) +int srs_client_send(struct ril_client *client, struct srs_message *message) { + struct srs_data *data; struct srs_header header; - void *data; - + void *buffer = NULL; + size_t length; struct timeval timeout; fd_set fds; + unsigned char *p; int rc; - if (srs_client_data == NULL || message == NULL) - return -EINVAL; + if (client == NULL || client->data == NULL || message == NULL) + return -1; - memset(&header, 0, sizeof(header)); - header.group = SRS_GROUP(message->command); - header.index = SRS_INDEX(message->command); - header.length = message->length + sizeof(header); + data = (struct srs_data *) client->data; + if (data->client_fd < 0) + return -1; - data = calloc(1, header.length); - memcpy(data, &header, sizeof(header)); - memcpy((void *) ((char *) data + sizeof(header)), message->data, message->length); + RIL_CLIENT_LOCK(client); - memset(&timeout, 0, sizeof(timeout)); - timeout.tv_usec = 300; + srs_header_setup(&header, message); + + length = header.length; + buffer = calloc(1, length); - if (srs_client_data->client_fd < 0) { - rc = -1; - goto complete; + memcpy(buffer, &header, sizeof(header)); + if (message->data != NULL && message->size > 0) { + p = (unsigned char *) buffer + sizeof(header); + memcpy(p, message->data, message->size); } - FD_ZERO(&fds); - FD_SET(srs_client_data->client_fd, &fds); + srs_log_send(client, message); - rc = select(srs_client_data->client_fd + 1, NULL, &fds, NULL, &timeout); + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 300; + + FD_ZERO(&fds); + FD_SET(data->client_fd, &fds); - if (!FD_ISSET(srs_client_data->client_fd, &fds)) { - RIL_LOGE("SRS write select failed on fd %d", srs_client_data->client_fd); - rc = -1; - goto complete; + rc = select(data->client_fd + 1, NULL, &fds, NULL, &timeout); + if (rc <= 0 || !FD_ISSET(data->client_fd, &fds)) { + RIL_LOGE("Polling %s client failed", client->name); + goto error; } - rc = write(srs_client_data->client_fd, data, header.length); - if (rc < (int) sizeof(struct srs_header)) { - RIL_LOGE("SRS write failed on fd %d with %d bytes", srs_client_data->client_fd, rc); - rc = -1; - goto complete; + rc = write(data->client_fd, buffer, length); + if (rc < (int) length) { + RIL_LOGE("Writing to %s client failed", client->name); + goto error; } + rc = 0; + goto complete; + +error: + rc = -1; + complete: - free(data); + if (buffer != NULL) + free(buffer); + + RIL_CLIENT_UNLOCK(client); return rc; } -int srs_client_send(struct srs_client_data *srs_client_data, unsigned short command, void *data, int length) +int srs_client_recv(struct ril_client *client, struct srs_message *message) { - struct srs_client_info *client; - struct srs_message message; + struct srs_data *data; + struct srs_header *header; + void *buffer = NULL; + size_t length; + struct timeval timeout; + fd_set fds; + unsigned char *p; int rc; - if (srs_client_data == NULL) + if (client == NULL || client->data == NULL || message == NULL) return -1; - memset(&message, 0, sizeof(message)); - message.command = command; - message.length = length; - message.data = data; + data = (struct srs_data *) client->data; + if (data->client_fd < 0) + return -1; + + RIL_CLIENT_LOCK(client); + + length = SRS_BUFFER_LENGTH; + buffer= calloc(1, length); + + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 300; + + FD_ZERO(&fds); + FD_SET(data->client_fd, &fds); + + rc = select(data->client_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0 || !FD_ISSET(data->client_fd, &fds)) { + RIL_LOGE("Polling %s client failed", client->name); + goto error; + } + + rc = read(data->client_fd, buffer, length); + if (rc < (int) sizeof(struct srs_header)) { + RIL_LOGE("Reading from %s client failed", client->name); + goto error; + } + + header = (struct srs_header *) buffer; - RIL_CLIENT_LOCK(srs_client_data->client); - rc = srs_client_send_message(srs_client_data, &message); - RIL_CLIENT_UNLOCK(srs_client_data->client); + srs_message_setup(header, message); - if (rc <= 0) { - RIL_LOGD("SRS client with fd %d terminated", srs_client_data->client_fd); + length = header->length - sizeof(struct srs_header); + if (length > 0) { + message->size = length; + message->data = calloc(1, length); - client = srs_client_info_find_fd(srs_client_data, srs_client_data->client_fd); - if (client != NULL) - srs_client_unregister(srs_client_data, client); - close(srs_client_data->client_fd); - srs_client_data->client_fd = -1; + p = (unsigned char *) buffer + sizeof(struct srs_header); + memcpy(message->data, p, length); } + srs_log_recv(client, message); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + RIL_CLIENT_UNLOCK(client); + return rc; } -int srs_send(unsigned short command, void *data, int length) +/* + * SRS server + */ + +int srs_server_open(struct ril_client *client) { - struct srs_client_data *srs_client_data; + struct srs_data *data; + int server_fd; + int flags; int rc; - if (ril_data.srs_client == NULL || ril_data.srs_client->data == NULL) - return -EINVAL; + if (client == NULL || client->data == NULL) + return -1; + + data = (struct srs_data *) client->data; + if (data->server_event_fd < 0) + return -1; - srs_client_data = (struct srs_client_data *) ril_data.srs_client->data; + RIL_CLIENT_LOCK(client); - RIL_LOGD("SEND SRS: fd=%d command=%d length=%d", srs_client_data->client_fd, command, length); - if (data != NULL && length > 0) { - RIL_LOGD("==== SRS DATA DUMP ===="); - hex_dump(data, length); - RIL_LOGD("======================="); + unlink(SRS_SOCKET_NAME); + +#if RIL_VERSION >= 6 + server_fd = socket_local_server(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); +#else + server_fd = socket_local_server(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); +#endif + if (server_fd < 0) { + RIL_LOGE("Opening %s server failed", client->name); + goto error; } - return srs_client_send(srs_client_data, command, data, length); + flags = fcntl(server_fd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(server_fd, F_SETFL, flags); + + data->server_fd = server_fd; + + eventfd_flush(data->server_event_fd); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); + + return rc; } -int srs_client_recv(struct srs_client_data *srs_client_data, struct srs_message *message) +int srs_server_close(struct ril_client *ril_client) { - struct srs_header *header; - void *data; - - struct timeval timeout; - fd_set fds; + struct srs_data *data; + struct srs_client *client; + eventfd_t event; int rc; - if (srs_client_data == NULL || message == NULL) + if (ril_client == NULL || ril_client->data == NULL) return -1; - data = calloc(1, SRS_DATA_MAX_SIZE); + data = (struct srs_data *) ril_client->data; + if (data->server_event_fd < 0) + return -1; - memset(&timeout, 0, sizeof(timeout)); - timeout.tv_usec = 300; + do { + client = srs_client_find(ril_client); + if (client == NULL) + break; - if (srs_client_data->client_fd < 0) { - rc = -1; - goto complete; - } + if (client->fd >= 0) + close(client->fd); - FD_ZERO(&fds); - FD_SET(srs_client_data->client_fd, &fds); + rc = srs_client_unregister(ril_client, client); + if (rc < 0) { + RIL_LOGE("Unregistering %s client failed", ril_client->name); + return -1; + } + } while (client != NULL); - rc = select(srs_client_data->client_fd + 1, &fds, NULL, NULL, &timeout); + RIL_CLIENT_LOCK(ril_client); - if (!FD_ISSET(srs_client_data->client_fd, &fds)) { - RIL_LOGE("SRS read select failed on fd %d", srs_client_data->client_fd); - rc = -1; - goto complete; + rc = eventfd_send(data->server_event_fd, SRS_SERVER_CLOSE); + if (rc < 0) { + RIL_LOGE("Sending %s server close event failed", ril_client->name); + goto error; } - rc = read(srs_client_data->client_fd, data, SRS_DATA_MAX_SIZE); - if (rc < (int) sizeof(struct srs_header)) { - RIL_LOGE("SRS read failed on fd %d with %d bytes", srs_client_data->client_fd, rc); - rc = -1; - goto complete; + if (data->server_fd >= 0) { + close(data->server_fd); + data->server_fd = -1; } - header = (struct srs_header *) data; + rc = 0; + goto complete; - memset(message, 0, sizeof(struct srs_message)); - message->command = SRS_COMMAND(header); - message->length = header->length - sizeof(struct srs_header); - message->data = NULL; - - if (message->length > 0) { - message->data = calloc(1, message->length); - memcpy(message->data, (void *) ((char *) data + sizeof(struct srs_header)), message->length); - } +error: + rc = -1; complete: - free(data); + RIL_CLIENT_UNLOCK(ril_client); return rc; } -void srs_control_ping(struct srs_message *message) +int srs_server_loop(struct ril_client *client) { - int caffe; + struct srs_data *data; + struct sockaddr_un client_addr; + socklen_t client_addr_len; + eventfd_t event; + int client_fd; + fd_set fds; + int fd_max; + int flags; + int rc; - if (message == NULL || message->data == NULL || message->length < (int) sizeof(int)) - return; + if (client == NULL || client->data == NULL) + return -1; - caffe = *((int *) message->data); + data = (struct srs_data *) client->data; + if (data->server_fd < 0 || data->server_event_fd < 0 || data->event_fd < 0) + return -1; - if (caffe == SRS_CONTROL_CAFFE) - srs_send(SRS_CONTROL_PING, &caffe, sizeof(caffe)); -} + while (1) { + if (!client->available) { + RIL_LOGE("%s client is not available", client->name); + return -1; + } -static int srs_server_open(void) -{ - int server_fd; - int t; + FD_ZERO(&fds); + FD_SET(data->server_fd, &fds); + FD_SET(data->server_event_fd, &fds); - for (t = 0 ; t < 5 ; t++) { - unlink(SRS_SOCKET_NAME); -#if RIL_VERSION >= 6 - server_fd = socket_local_server(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); -#else - server_fd = socket_local_server(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); -#endif - if (server_fd >= 0) - return server_fd; + fd_max = data->server_fd > data->server_event_fd ? data->server_fd : data->server_event_fd; + + rc = select(fd_max + 1, &fds, NULL, NULL, NULL); + if (rc < 0) { + RIL_LOGE("Polling %s server failed", client->name); + return -1; + } + + if (FD_ISSET(data->server_event_fd, &fds)) { + rc = eventfd_recv(data->server_event_fd, &event); + if (rc < 0) + return -1; + + switch (event) { + case SRS_SERVER_CLOSE: + return 0; + } + } + + if (!FD_ISSET(data->server_fd, &fds)) + continue; + + client_fd = accept(data->server_fd, (struct sockaddr *) &client_addr, &client_addr_len); + if (client_fd < 0) { + RIL_LOGE("Accepting new %s client failed", client->name); + return -1; + } + + flags = fcntl(client_fd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(client_fd, F_SETFL, flags); + + rc = srs_client_register(client, client_fd); + if (rc < 0) { + RIL_LOGE("Registering new %s client failed", client->name); + return -1; + } + + RIL_LOGD("Registered new %s client", client->name); + + rc = eventfd_send(data->event_fd, SRS_CLIENT_CHANGE); + if (rc < 0) { + RIL_LOGE("Sending %s change event failed", client->name); + return -1; + } } - return -1; + return 0; } -void *srs_client_read_loop(void *data) +void *srs_server_thread(void *data) { - struct srs_client_info *client; - struct srs_client_data *srs_client_data; - struct srs_message message; - struct timeval timeout; - fd_set fds; - int fd_max; - int fd; + struct ril_client *client; + int failures = 0; int rc; if (data == NULL) - pthread_exit(NULL); + return NULL; - srs_client_data = (struct srs_client_data *) data; + client = (struct ril_client *) data; - while (srs_client_data->running) { - FD_ZERO(&fds); + do { + if (failures) { + rc = srs_server_close(client); + if (rc < 0) + goto failure; - SRS_CLIENT_LOCK(); - fd_max = srs_client_info_fill_fd_set(srs_client_data, &fds); - SRS_CLIENT_UNLOCK(); + rc = srs_server_open(client); + if (rc < 0) + goto failure; + } - if (fd_max < 0) { - usleep(3000); - continue; + rc = srs_server_loop(client); + if (rc < 0) { + RIL_LOGE("%s server loop failed", client->name); + goto failure; + } else { + RIL_LOGE("%s server loop terminated", client->name); + break; } - timeout.tv_sec = 0; - timeout.tv_usec = 3000; +failure: + failures++; + } while (failures < RIL_CLIENT_RETRY_COUNT); - select(fd_max + 1, &fds, NULL, NULL, &timeout); + srs_server_close(client); - SRS_CLIENT_LOCK(); - while ((fd = srs_client_info_get_fd_set(srs_client_data, &fds)) >= 0) { - srs_client_data->client_fd = fd; + RIL_LOGD("Stopped %s server loop", client->name); - RIL_CLIENT_LOCK(srs_client_data->client); - rc = srs_client_recv(srs_client_data, &message); - if (rc <= 0) { - RIL_LOGD("SRS client with fd %d terminated", fd); + return NULL; +} - client = srs_client_info_find_fd(srs_client_data, fd); - if (client != NULL) - srs_client_unregister(srs_client_data, client); - close(fd); +/* + * SRS client + */ - RIL_CLIENT_UNLOCK(srs_client_data->client); - continue; - } - RIL_CLIENT_UNLOCK(srs_client_data->client); +int srs_create(struct ril_client *client) +{ + struct srs_data *data; + int server_event_fd = -1; + int event_fd = -1; + int rc; - RIL_LOGD("RECV SRS: fd=%d command=%d length=%d", fd, message.command, message.length); - if (message.data != NULL && message.length > 0) { - RIL_LOGD("==== SRS DATA DUMP ===="); - hex_dump(message.data, message.length); - RIL_LOGD("======================="); - } + if (client == NULL) + return -1; - srs_dispatch(&message); + signal(SIGPIPE, SIG_IGN); - if (message.data != NULL && message.length > 0) - free(message.data); + RIL_CLIENT_LOCK(client); - srs_client_data->client_fd = -1; - } - SRS_CLIENT_UNLOCK(); + client->available = 0; + + data = (struct srs_data *) calloc(1, sizeof(struct srs_data)); + data->server_fd = -1; + data->client_fd = -1; + + server_event_fd = eventfd(0, EFD_NONBLOCK); + if (server_event_fd < 0) { + RIL_LOGE("Creating %s server event failed", client->name); + goto error; } - pthread_exit(NULL); - return NULL; + event_fd = eventfd(0, EFD_NONBLOCK); + if (event_fd < 0) { + RIL_LOGE("Creating %s event failed", client->name); + goto error; + } + + data->server_event_fd = server_event_fd; + data->event_fd = event_fd; + + client->data = data; + + rc = 0; + goto complete; + +error: + if (server_event_fd >= 0) + close(server_event_fd); + + if (event_fd >= 0) + close(event_fd); + + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); + + return rc; } -int srs_read_loop(struct ril_client *client) +int srs_destroy(struct ril_client *client) { - struct srs_client_data *srs_client_data; + struct srs_data *data; - struct sockaddr_un client_addr; - int client_addr_len; + if (client == NULL || client->data == NULL) + return -1; + + data = (struct srs_data *) client->data; + + if (client->available) + srs_close(client); + + RIL_CLIENT_LOCK(client); + + client->available = 0; + + if (data->server_event_fd >= 0) + close(data->server_event_fd); + + if (data->event_fd >= 0) + close(data->event_fd); + + memset(data, 0, sizeof(struct srs_data)); + free(data); + + client->data = NULL; + + RIL_CLIENT_UNLOCK(client); + + return 0; +} + +int srs_open(struct ril_client *client) +{ + struct srs_data *data; pthread_attr_t attr; - int flags; - int fd; int rc; if (client == NULL || client->data == NULL) - return -EINVAL; + return -1; - srs_client_data = (struct srs_client_data *) client->data; + data = (struct srs_data *) client->data; + if (data->event_fd < 0) + return -1; + + rc = srs_server_open(client); + if (rc < 0) { + RIL_LOGE("Opening %s server failed", client->name); + return -1; + } + + RIL_CLIENT_LOCK(client); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - srs_client_data->running = 1; + rc = pthread_create(&data->server_thread, &attr, srs_server_thread, (void *) client); + if (rc != 0) { + RIL_LOGE("Starting %s server loop failed", client->name); + goto error; + } - rc = pthread_create(&srs_client_data->thread, &attr, srs_client_read_loop, (void *) srs_client_data); - if (rc < 0) { - RIL_LOGE("Unable to create SRS client read loop thread"); + RIL_LOGD("Started %s server loop", client->name); + + eventfd_flush(data->event_fd); + + client->available = 1; + + rc = 0; + goto complete; + +error: + srs_server_close(client); + + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); + + return rc; +} + +int srs_close(struct ril_client *ril_client) +{ + struct srs_data *data; + struct srs_client *client; + eventfd_t event; + int rc; + + if (ril_client == NULL || ril_client->data == NULL) return -1; - } - while (srs_client_data->server_fd >= 0) { - fd = accept(srs_client_data->server_fd, (struct sockaddr *) &client_addr, - &client_addr_len); - if (fd < 0) { - RIL_LOGE("Unable to accept new SRS client"); - break; - } + data = (struct srs_data *) ril_client->data; + if (data->event_fd < 0) + return -1; - flags = fcntl(fd, F_GETFL); - flags |= O_NONBLOCK; - fcntl(fd, F_SETFL, flags); + RIL_CLIENT_LOCK(ril_client); - RIL_LOGD("Accepted new SRS client from fd %d", fd); + rc = eventfd_send(data->event_fd, SRS_CLIENT_CLOSE); + if (rc < 0) { + RIL_LOGE("Sending %s close event failed", ril_client->name); + RIL_CLIENT_UNLOCK(ril_client); - SRS_CLIENT_LOCK(); - rc = srs_client_register(srs_client_data, fd); - SRS_CLIENT_UNLOCK(); - if (rc < 0) { - RIL_LOGE("Unable to register SRS client"); - break; - } + return -1; } - RIL_LOGE("SRS server failure"); + data->client_fd = -1; + + RIL_CLIENT_UNLOCK(ril_client); + + rc = srs_server_close(ril_client); + if (rc < 0) { + RIL_LOGE("Closing %s server failed", ril_client->name); + return -1; + } - srs_client_data->running = 0; + rc = srs_client_flush(ril_client); + if (rc < 0) { + RIL_LOGE("Flushing %s client failed", ril_client->name); + return -1; + } - // Wait for the thread to finish - pthread_join(srs_client_data->thread, NULL); + pthread_join(data->server_thread, NULL); return 0; } -int srs_create(struct ril_client *client) +int srs_dispatch(struct ril_client *client, struct srs_message *message) { - struct srs_client_data *srs_client_data; + unsigned int i; + int rc; - if (client == NULL) - return -EINVAL; + if (client == NULL || message == NULL || ril_data == NULL) + return -1; - RIL_LOGD("Creating new SRS client"); + RIL_LOCK(); - signal(SIGPIPE, SIG_IGN); + for (i = 0; i < srs_dispatch_handlers_count; i++) { + if (srs_dispatch_handlers[i].handler == NULL) + continue; - srs_client_data = (struct srs_client_data *) calloc(1, sizeof(struct srs_client_data)); + if (srs_dispatch_handlers[i].command == message->command) { + rc = srs_dispatch_handlers[i].handler(message); + if (rc < 0) { + RIL_LOGE("Handling %s message failed", client->name); + goto error; + } - srs_client_data->server_fd = srs_server_open(); - if (srs_client_data->server_fd < 0) { - RIL_LOGE("SRS server creation failed"); - goto error; + rc = 0; + goto complete; + } } - pthread_mutex_init(&srs_client_data->mutex, NULL); - - srs_client_data->client = client; - client->data = (void *) srs_client_data; + RIL_LOGD("Unhandled %s message: %s", client->name, srs_command_string(message->command)); - return 0; + rc = 0; + goto complete; error: - free(srs_client_data); + rc = -1; - return -1; +complete: + RIL_UNLOCK(); + + return rc; } -int srs_destroy(struct ril_client *client) +int srs_loop(struct ril_client *ril_client) { - struct srs_client_data *srs_client_data = NULL; - struct srs_client_info *client_info; + struct srs_data *data; + struct srs_client *client; + struct srs_message message; + eventfd_t event; + fd_set fds; + int fd_max; + int rc; - if (client == NULL || client->data == NULL) { - RIL_LOGE("Client was already destroyed"); - return 0; - } + if (ril_client == NULL || ril_client->data == NULL) + return -1; + + data = (struct srs_data *) ril_client->data; + if (data->event_fd < 0) + return -1; - srs_client_data = (struct srs_client_data *) client->data; + while (1) { + if (!ril_client->available) { + RIL_LOGE("%s client is not available", ril_client->name); + return -1; + } - pthread_mutex_destroy(&srs_client_data->mutex); + fd_max = srs_client_fd_set_setup(ril_client, &fds); - while ((client_info = srs_client_info_find(srs_client_data)) != NULL) { - close(client_info->fd); - srs_client_unregister(srs_client_data, client_info); - } + FD_SET(data->event_fd, &fds); - if (srs_client_data->server_fd > 0) - close(srs_client_data->server_fd); + fd_max = fd_max > data->event_fd ? fd_max : data->event_fd; - srs_client_data->server_fd = -1; - srs_client_data->client_fd = -1; - srs_client_data->clients = NULL; - srs_client_data->running = 0; + rc = select(fd_max + 1, &fds, NULL, NULL, NULL); + if (rc < 0) { + RIL_LOGE("Polling %s client failed", ril_client->name); + return -1; + } - free(srs_client_data); - client->data = NULL; + if (FD_ISSET(data->event_fd, &fds)) { + rc = eventfd_read(data->event_fd, &event); + if (rc < 0) + return -1; + + switch (event) { + case SRS_CLIENT_CLOSE: + return 0; + case SRS_CLIENT_CHANGE: + break; + case SRS_CLIENT_IO_ERROR: + if (client->fd >= 0) + close(client->fd); + + data->client_fd = -1; + + srs_client_unregister(ril_client, client); + break; + } + } + + do { + client = srs_client_find_fd_set(ril_client, &fds); + if (client == NULL) + break; + + data->client_fd = client->fd; + + memset(&message, 0, sizeof(message)); + + RIL_LOCK(); + acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING); + + rc = srs_client_recv(ril_client, &message); + if (rc < 0) { + RIL_LOGE("Receiving from %s client failed", ril_client->name); + + release_wake_lock(RIL_VERSION_STRING); + RIL_UNLOCK(); + + if (client->fd >= 0) + close(client->fd); + + data->client_fd = -1; + + srs_client_unregister(ril_client, client); + continue; + } + + RIL_UNLOCK(); + + rc = srs_dispatch(ril_client, &message); + if (rc < 0) { + RIL_LOGE("Dispatching %s message failed", ril_client->name); + + if (message.data != NULL && message.size > 0) + free(message.data); + + if (client->fd >= 0) + close(client->fd); + + data->client_fd = -1; + + srs_client_unregister(ril_client, client); + continue; + } + + if (message.data != NULL && message.size > 0) + free(message.data); + + data->client_fd = -1; + } while (client != NULL); + } return 0; } -struct ril_client_funcs srs_client_funcs = { +/* + * RIL client + */ + +struct ril_client_handlers srs_handlers = { .create = srs_create, .destroy = srs_destroy, - .read_loop = srs_read_loop, + .open = srs_open, + .close = srs_close, + .loop = srs_loop, +}; + + +struct ril_client_callbacks srs_callbacks = { + .request_register = NULL, + .request_unregister = NULL, + .flush = NULL, +}; + +struct ril_client srs_client = { + .id = RIL_CLIENT_SRS, + .name = "SRS", + .critical = 0, + .handlers = &srs_handlers, + .callbacks = &srs_callbacks, }; @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,39 +20,94 @@ #ifndef _SRS_H_ #define _SRS_H_ -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/select.h> -#include <sys/un.h> +#include <stdlib.h> -#include <arpa/inet.h> -#include <netinet/in.h> +#include <samsung-ril.h> -#include <samsung-ril-socket.h> +/* + * Values + */ + +#define SRS_CLIENT_CLOSE 0x00 +#define SRS_SERVER_CLOSE 0x01 +#define SRS_CLIENT_CHANGE 0x02 +#define SRS_CLIENT_IO_ERROR 0x03 -#define SRS_CLIENT_LOCK() pthread_mutex_lock(&srs_client_data->mutex) -#define SRS_CLIENT_UNLOCK() pthread_mutex_unlock(&srs_client_data->mutex) +/* + * Structures + */ -struct srs_client_info { +struct srs_client { int fd; }; -struct srs_client_data { - struct ril_client *client; - +struct srs_data { int server_fd; int client_fd; + int server_event_fd; + int event_fd; + + pthread_t server_thread; + struct list_head *clients; +}; - pthread_t thread; - pthread_mutex_t mutex; - int running; +struct srs_dispatch_handler { + unsigned short command; + int (*handler)(struct srs_message *message); }; -extern struct ril_client_funcs srs_client_funcs; +/* + * Helpers + */ + +/* Utils */ +const char *srs_command_string(unsigned short command); +void srs_log_send(struct ril_client *client, struct srs_message *message); +void srs_log_recv(struct ril_client *client, struct srs_message *message); +int srs_header_setup(struct srs_header *header, + const struct srs_message *message); +int srs_message_setup(const struct srs_header *header, + struct srs_message *message); + +/* SRS */ +int srs_send(unsigned short command, const void *data, size_t size); +int srs_control_ping(struct srs_message *message); + +/* SRS client */ +int srs_client_register(struct ril_client *ril_client, int fd); +int srs_client_unregister(struct ril_client *ril_client, + struct srs_client *client); +int srs_client_flush(struct ril_client *ril_client); +struct srs_client *srs_client_find(struct ril_client *ril_client); +struct srs_client *srs_client_find_fd(struct ril_client *ril_client, int fd); +struct srs_client *srs_client_find_fd_set(struct ril_client *ril_client, + fd_set *fds); +int srs_client_fd_set_setup(struct ril_client *ril_client, fd_set *fds); +int srs_client_send(struct ril_client *client, struct srs_message *message); +int srs_client_recv(struct ril_client *client, struct srs_message *message); + +/* SRS server */ +int srs_server_open(struct ril_client *client); +int srs_server_close(struct ril_client *client); +int srs_server_loop(struct ril_client *client); +void *srs_server_thread(void *data); + +/* SRS client */ +int srs_create(struct ril_client *client); +int srs_destroy(struct ril_client *client); +int srs_open(struct ril_client *client); +int srs_close(struct ril_client *ril_client); +int srs_dispatch(struct ril_client *client, struct srs_message *message); +int srs_loop(struct ril_client *ril_client); + +/* + * RIL client + */ -int srs_send(unsigned short command, void *data, int length); -void srs_control_ping(struct srs_message *message); +extern struct ril_client_handlers srs_handlers; +extern struct ril_client_callbacks srs_callbacks; +extern struct ril_client srs_client; #endif @@ -1,251 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#define LOG_TAG "RIL-SS" -#include <utils/Log.h> - -#include "samsung-ril.h" -#include "util.h" - -void ipc_ss_ussd_complete(struct ipc_message_info *info) -{ - struct ipc_gen_phone_res *phone_res; - int rc; - - phone_res = (struct ipc_gen_phone_res *) info->data; - - rc = ipc_gen_phone_res_check(phone_res); - if (rc < 0) { - RIL_LOGE("There was an error, aborting USSD request"); - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - ril_data.state.ussd_state = 0; - - return; - } - - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, NULL, 0); -} - -void ril_request_send_ussd(RIL_Token t, void *data, size_t length) -{ - char *data_enc = NULL; - int data_enc_len = 0; - - char *message =NULL; - struct ipc_ss_ussd *ussd = NULL; - - int message_size = 0xc0; - - if (data == NULL || length < (int) sizeof(char *)) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - switch (ril_data.state.ussd_state) { - case 0: - case IPC_SS_USSD_NO_ACTION_REQUIRE: - case IPC_SS_USSD_TERMINATED_BY_NET: - case IPC_SS_USSD_OTHER_CLIENT: - case IPC_SS_USSD_NOT_SUPPORT: - case IPC_SS_USSD_TIME_OUT: - RIL_LOGD("USSD Tx encoding is GSM7"); - - data_enc_len = ascii2gsm7_ussd(data, (unsigned char**)&data_enc, length); - if (data_enc_len > message_size) { - RIL_LOGE("USSD message size is too long, aborting"); - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - - free(data_enc); - - return; - } - - message = malloc(message_size); - memset(message, 0, message_size); - - ussd = (struct ipc_ss_ussd *) message; - ussd->state = IPC_SS_USSD_NO_ACTION_REQUIRE; - ussd->dcs = 0x0f; // GSM7 in that case - ussd->length = data_enc_len; - - memcpy((void *) (message + sizeof(struct ipc_ss_ussd)), data_enc, data_enc_len); - - free(data_enc); - - break; - case IPC_SS_USSD_ACTION_REQUIRE: - default: - RIL_LOGD("USSD Tx encoding is ASCII"); - - data_enc_len = asprintf(&data_enc, "%s", (char*)data); - - if (data_enc_len > message_size) { - RIL_LOGE("USSD message size is too long, aborting"); - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - - free(data_enc); - - return; - } - - message = malloc(message_size); - memset(message, 0, message_size); - - ussd = (struct ipc_ss_ussd *) message; - ussd->state = IPC_SS_USSD_ACTION_REQUIRE; - ussd->dcs = 0x0f; // ASCII in that case - ussd->length = data_enc_len; - - memcpy((void *) (message + sizeof(struct ipc_ss_ussd)), data_enc, data_enc_len); - - free(data_enc); - - break; - } - - if (message == NULL) { - RIL_LOGE("USSD message is empty, aborting"); - - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SS_USSD, - ipc_ss_ussd_complete); - - ipc_fmt_send(IPC_SS_USSD, IPC_TYPE_EXEC, (void *) message, message_size, ril_request_get_id(t)); - - return; - -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_cancel_ussd(RIL_Token t, void *data, size_t length) -{ - struct ipc_ss_ussd ussd; - - if (ril_radio_state_complete(RADIO_STATE_OFF, t)) - return; - - memset(&ussd, 0, sizeof(ussd)); - - ussd.state = IPC_SS_USSD_TERMINATED_BY_NET; - ril_data.state.ussd_state = IPC_SS_USSD_TERMINATED_BY_NET; - - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_SS_USSD); - - ipc_fmt_send(IPC_SS_USSD, IPC_TYPE_EXEC, (void *) &ussd, sizeof(ussd), ril_request_get_id(t)); -} - -void ipc2ril_ussd_state(struct ipc_ss_ussd *ussd, char *message[2]) -{ - if (ussd == NULL || message == NULL) - return; - - switch (ussd->state) { - case IPC_SS_USSD_NO_ACTION_REQUIRE: - asprintf(&message[0], "%d", 0); - break; - case IPC_SS_USSD_ACTION_REQUIRE: - asprintf(&message[0], "%d", 1); - break; - case IPC_SS_USSD_TERMINATED_BY_NET: - asprintf(&message[0], "%d", 2); - break; - case IPC_SS_USSD_OTHER_CLIENT: - asprintf(&message[0], "%d", 3); - break; - case IPC_SS_USSD_NOT_SUPPORT: - asprintf(&message[0], "%d", 4); - break; - case IPC_SS_USSD_TIME_OUT: - asprintf(&message[0], "%d", 5); - break; - } -} - -void ipc_ss_ussd(struct ipc_message_info *info) -{ - char *data_dec = NULL; - int data_dec_len = 0; - SmsCodingScheme codingScheme; - - char *message[2]; - - struct ipc_ss_ussd *ussd = NULL; - unsigned char state; - - if (info->data == NULL || info->length < sizeof(struct ipc_ss_ussd)) - goto error; - - memset(message, 0, sizeof(message)); - - ussd = (struct ipc_ss_ussd *) info->data; - - ipc2ril_ussd_state(ussd, message); - - ril_data.state.ussd_state = ussd->state; - - if (ussd->length > 0 && info->length > 0 && info->data != NULL) { - codingScheme = sms_get_coding_scheme(ussd->dcs); - switch (codingScheme) { - case SMS_CODING_SCHEME_GSM7: - RIL_LOGD("USSD Rx encoding is GSM7"); - - data_dec_len = gsm72ascii(info->data - + sizeof(struct ipc_ss_ussd), &data_dec, info->length - sizeof(struct ipc_ss_ussd)); - asprintf(&message[1], "%s", data_dec); - message[1][data_dec_len] = '\0'; - - break; - case SMS_CODING_SCHEME_UCS2: - RIL_LOGD("USSD Rx encoding %x is UCS2", ussd->dcs); - - data_dec_len = info->length - sizeof(struct ipc_ss_ussd); - message[1] = malloc(data_dec_len * 4 + 1); - - int i, result = 0; - char *ucs2 = (char*)info->data + sizeof(struct ipc_ss_ussd); - for (i = 0; i < data_dec_len; i += 2) { - int c = (ucs2[i] << 8) | ucs2[1 + i]; - result += utf8_write(message[1], result, c); - } - message[1][result] = '\0'; - break; - default: - RIL_LOGD("USSD Rx encoding %x is unknown, assuming ASCII", - ussd->dcs); - - data_dec_len = info->length - sizeof(struct ipc_ss_ussd); - asprintf(&message[1], "%s", info->data + sizeof(struct ipc_ss_ussd)); - message[1][data_dec_len] = '\0'; - break; - } - } - - ril_request_unsolicited(RIL_UNSOL_ON_USSD, message, sizeof(message)); - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} @@ -1,244 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#define LOG_TAG "RIL-SVC" -#include <utils/Log.h> - -#include "samsung-ril.h" -#include "util.h" - -int ril_oem_hook_svc_session_start(void) -{ - if (ril_data.oem_hook_svc_session != NULL) { - RIL_LOGE("OEM hook SVC session was already started"); - return -1; - } - - ril_data.oem_hook_svc_session = calloc(1, sizeof(struct ril_oem_hook_svc_session)); - - return 0; -} - -void ril_oem_hook_svc_session_stop(void) -{ - if (ril_data.oem_hook_svc_session == NULL) { - RIL_LOGE("OEM hook SVC session was already stopped"); - return; - } - - if (ril_data.oem_hook_svc_session->display_screen != NULL) - free(ril_data.oem_hook_svc_session->display_screen); - - free(ril_data.oem_hook_svc_session); - ril_data.oem_hook_svc_session = NULL; -} - -void ipc_svc_display_screen(struct ipc_message_info *info) -{ - char svc_end_message[] = "Samsung-RIL is asking you to End service mode"; - struct ipc_svc_display_screen_header *header; - struct ipc_svc_display_screen_data *data; - - if (info == NULL || info->data == NULL || info->length < sizeof(header->count)) - return; - - if (ril_data.oem_hook_svc_session == NULL) - goto error; - - header = (struct ipc_svc_display_screen_header *) info->data; - - if (header->count == 0) { - if (ril_data.oem_hook_svc_session->token != RIL_TOKEN_NULL) { - ril_request_complete(ril_data.oem_hook_svc_session->token, RIL_E_SUCCESS, &svc_end_message, sizeof(svc_end_message)); - ril_data.oem_hook_svc_session->token = RIL_TOKEN_NULL; - } - - ril_oem_hook_svc_session_stop(); - - return; - } - - data = (struct ipc_svc_display_screen_data *) ((unsigned char *) info->data + sizeof(struct ipc_svc_display_screen_header)); - - // Invalid responses don't start at index 0 - if (data->index != 0) - return; - - if (ril_data.oem_hook_svc_session->display_screen != NULL) { - free(ril_data.oem_hook_svc_session->display_screen); - ril_data.oem_hook_svc_session->display_screen = NULL; - ril_data.oem_hook_svc_session->display_screen_length = 0; - } - - ril_data.oem_hook_svc_session->display_screen_length = header->count * sizeof(struct ipc_svc_display_screen_data); - ril_data.oem_hook_svc_session->display_screen = malloc(ril_data.oem_hook_svc_session->display_screen_length); - memcpy(ril_data.oem_hook_svc_session->display_screen, data, ril_data.oem_hook_svc_session->display_screen_length); - - if (ril_data.oem_hook_svc_session->token != RIL_TOKEN_NULL) { - ril_request_complete(ril_data.oem_hook_svc_session->token, RIL_E_SUCCESS, ril_data.oem_hook_svc_session->display_screen, ril_data.oem_hook_svc_session->display_screen_length); - - ril_data.oem_hook_svc_session->token = RIL_TOKEN_NULL; - } - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ipc_svc_callback(struct ipc_message_info *info) -{ - struct ipc_gen_phone_res *phone_res; - int rc; - - if (info == NULL || info->data == NULL || info->length < (int) sizeof(struct ipc_gen_phone_res)) - return; - - if (ril_data.oem_hook_svc_session == NULL) - goto error; - - phone_res = (struct ipc_gen_phone_res *) info->data; - - rc = ipc_gen_phone_res_check(phone_res); - if (rc < 0) - goto error; - - if (ril_data.oem_hook_svc_session->token != RIL_TOKEN_NULL) { - RIL_LOGE("%s: Another token is waiting", __func__); - goto error; - } - - ril_data.oem_hook_svc_session->token = ril_request_get_token(info->aseq); - - return; - -error: - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); -} - -void ril_request_oem_hook_raw(RIL_Token token, void *data, int length) -{ - RIL_OEMHookHeader *header; - RIL_OEMHookSvcEnterMode *svc_enter_mode; - RIL_OEMHookSvcEndMode *svc_end_mode; - RIL_OEMHookSvcKey *svc_key; - struct ipc_svc_enter_data svc_enter_data; - struct ipc_svc_end_data svc_end_data; - struct ipc_svc_pro_keycode_data svc_pro_keycode_data; - int svc_length; - int rc; - - if (data == NULL || length < (int) sizeof(RIL_OEMHookHeader)) - goto error; - - if (ril_radio_state_complete(RADIO_STATE_OFF, token)) - return; - - header = (RIL_OEMHookHeader *) data; - - // Only SVC is supported - if (header->tag != RIL_OEM_HOOK_TAG_SVC) - goto error; - - svc_length = (header->length & 0xff) << 8 | (header->length & 0xff00) >> 8; - - switch (header->command) { - case RIL_OEM_COMMAND_SVC_ENTER_MODE: - if (svc_length < (int) (sizeof(RIL_OEMHookHeader) + sizeof(RIL_OEMHookSvcEnterMode))) - goto error; - - svc_enter_mode = (RIL_OEMHookSvcEnterMode *) ((unsigned char *) data + sizeof(RIL_OEMHookHeader)); - - if (svc_enter_mode->query) { - if (ril_data.oem_hook_svc_session == NULL) - goto error; - - if (ril_data.oem_hook_svc_session->display_screen != NULL && ril_data.oem_hook_svc_session->display_screen_length > 0) - ril_request_complete(token, RIL_E_SUCCESS, ril_data.oem_hook_svc_session->display_screen, ril_data.oem_hook_svc_session->display_screen_length); - else - goto error; - } else { - rc = ril_oem_hook_svc_session_start(); - if (rc < 0) { - RIL_LOGE("%s: Unable to start OEM hook SVC session", __func__); - goto error; - } - - memset(&svc_enter_data, 0, sizeof(svc_enter_data)); - svc_enter_data.mode = svc_enter_mode->mode; - svc_enter_data.type = svc_enter_mode->type; - - if (svc_enter_data.mode == IPC_SVC_MODE_MONITOR) - svc_enter_data.unknown = 0x00; - else - svc_enter_data.unknown = 0x10; - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(token), IPC_SVC_ENTER, ipc_svc_callback); - - ipc_fmt_send(IPC_SVC_ENTER, IPC_TYPE_SET, (unsigned char *) &svc_enter_data, sizeof(svc_enter_data), ril_request_get_id(token)); - } - break; - case RIL_OEM_COMMAND_SVC_END_MODE: - if (svc_length < (int) (sizeof(RIL_OEMHookHeader) + sizeof(RIL_OEMHookSvcEndMode))) - goto error; - - svc_end_mode = (RIL_OEMHookSvcEndMode *) ((unsigned char *) data + sizeof(RIL_OEMHookHeader)); - - ril_oem_hook_svc_session_stop(); - - memset(&svc_end_data, 0, sizeof(svc_end_data)); - svc_end_data.mode = svc_end_mode->mode; - - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(token), IPC_SVC_END); - - ipc_fmt_send(IPC_SVC_END, IPC_TYPE_SET, (unsigned char *) &svc_end_data, sizeof(svc_end_data), ril_request_get_id(token)); - break; - case RIL_OEM_COMMAND_SVC_KEY: - if (svc_length < (int) (sizeof(RIL_OEMHookHeader) + sizeof(RIL_OEMHookSvcKey))) - goto error; - - svc_key = (RIL_OEMHookSvcKey *) ((unsigned char *) data + sizeof(RIL_OEMHookHeader)); - - if (svc_key->query) { - if (ril_data.oem_hook_svc_session == NULL) - goto error; - - if (ril_data.oem_hook_svc_session->display_screen != NULL && ril_data.oem_hook_svc_session->display_screen_length > 0) - ril_request_complete(token, RIL_E_SUCCESS, ril_data.oem_hook_svc_session->display_screen, ril_data.oem_hook_svc_session->display_screen_length); - else - goto error; - } else { - if (ril_data.oem_hook_svc_session == NULL) - goto error; - - memset(&svc_pro_keycode_data, 0, sizeof(svc_pro_keycode_data)); - svc_pro_keycode_data.key = svc_key->key; - - ipc_gen_phone_res_expect_to_func(ril_request_get_id(token), IPC_SVC_PRO_KEYCODE, ipc_svc_callback); - - ipc_fmt_send(IPC_SVC_PRO_KEYCODE, IPC_TYPE_SET, (unsigned char *) &svc_pro_keycode_data, sizeof(svc_pro_keycode_data), ril_request_get_id(token)); - } - break; - } - - return; - -error: - ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); -} @@ -1,486 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> - * - * Samsung-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. - * - * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <time.h> - -#define LOG_TAG "RIL-UTIL" -#include <utils/Log.h> -#include "util.h" - -#include "samsung-ril.h" - -/* - * List - */ - -struct list_head *list_head_alloc(void *data, struct list_head *prev, struct list_head *next) -{ - struct list_head *list; - - list = calloc(1, sizeof(struct list_head)); - if (list == NULL) - return NULL; - - 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); -} - -/* - * Converts a hexidecimal string to binary - */ -void hex2bin(const char *data, int length, unsigned char *buf) -{ - int i = 0; - char b = 0; - unsigned char *p = buf; - - length ^= 0x01; - - while (i < length) { - b = 0; - - if (data[i] - '0' < 10) - b = data[i] - '0'; - else if (data[i] - 'a' < 7) - b = data[i] - 'a' + 10; - else if (data[i] - 'A' < 7) - b = data[i] - 'A' + 10; - i++; - - b = (b << 4); - - if (data[i] - '0' < 10) - b |= data[i] - '0'; - else if (data[i] - 'a' < 7) - b |= data[i] - 'a' + 10; - else if (data[i] - 'A' < 7) - b |= data[i] - 'A' + 10; - i++; - - *p++ = b; - } -} - -/* - * Converts binary data to a hexidecimal string - */ -void bin2hex(const unsigned char *data, int length, char *buf) -{ - int i; - char b; - char *p = buf; - - for (i = 0; i < length; i++) { - b = 0; - - b = (data[i] >> 4 & 0x0f); - b += (b < 10) ? '0' : ('a' - 10); - *p++ = b; - - b = (data[i] & 0x0f); - b += (b < 10) ? '0' : ('a' - 10); - *p++ = b; - } - - *p = '\0'; -} - -/* - * Converts GSM7 (8 bits) data to ASCII (7 bits) - */ -int gsm72ascii(unsigned char *data, char **data_dec, int length) -{ - int t, u, d, o = 0; - int i; - - int dec_length; - char *dec; - - dec_length = ((length * 8) - ((length * 8) % 7) ) / 7; - dec = malloc(dec_length); - - memset(dec, 0, dec_length); - - for (i = 0 ; i < length ; i++) - { - d = 7 - i % 7; - if (d == 7 && i != 0) - o++; - - t = (data[i] - (((data[i] >> d) & 0xff) << d)); - u = (data[i] >> d) & 0xff; - - dec[i+o]+=t << (i + o) % 8; - - if (u) - dec[i+1+o]+=u; - } - - *data_dec = dec; - - return dec_length; -} - -/* - * Converts ASCII (7 bits) data to GSM7 (8 bits) - */ -int ascii2gsm7_ussd(char *data, unsigned char **data_enc, int length) -{ - int d_off, d_pos, a_off, a_pos = 0; - int i; - - int enc_length; - unsigned char *enc; - - enc_length = ((length * 7) - (length * 7) % 8) / 8; - enc_length += (length * 7) % 8 > 0 ? 1 : 0; - - //FIXME: why does samsung does that? - enc_length++; - - enc = malloc(enc_length); - memset(enc, 0, enc_length); - - for (i = 0 ; i < length ; i++) - { - // offset from the right of data to keep - d_off = i % 8; - - // position of the data we keep - d_pos = ((i * 7) - (i * 7) % 8) / 8; - d_pos += (i * 7) % 8 > 0 ? 1 : 0; - - // adding the data with correct offset - enc[d_pos] |= data[i] >> d_off; - - // numbers of bits to omit to get data to add another place - a_off = 8 - d_off; - // position (on the encoded feed) of the data to add - a_pos = d_pos - 1; - - // adding the data to add at the correct position - enc[a_pos] |= data[i] << a_off; - } - - *data_enc = enc; - - //FIXME: what is going on here? - enc[enc_length - 2] |= 0x30; - enc[enc_length - 1] = 0x02; - - return enc_length; -} - -size_t ascii2gsm7(char *ascii, unsigned char *gsm7) -{ - int ascii_length; - int gsm7_length; - int offset; - - unsigned char *p; - int i; - - if (ascii == NULL) - return -1; - - ascii_length = strlen(ascii); - - gsm7_length = ((ascii_length * 7) - (ascii_length * 7) % 8) / 8; - gsm7_length = (ascii_length * 7) % 8 > 0 ? gsm7_length + 1 : gsm7_length; - - if (gsm7 == NULL) - return gsm7_length; - - memset(gsm7, 0, gsm7_length); - - offset = 0; - p = gsm7; - - for (i = 0; i < ascii_length; i++) { - *p |= ((ascii[i] & 0x7f) >> offset) & 0xff; - - if (offset) { - p--; - *p |= ((ascii[i] & ((1 << (offset + 1)) - 1)) << (8 - offset)) & 0xff; - p++; - } - - if (offset < 7) - p++; - - offset++; - offset %= 8; - } - - return gsm7_length; -} - -void hex_dump(void *data, int size) -{ - /* dumps size bytes of *data to stdout. Looks like: - * [0000] 75 6E 6B 6E 6F 77 6E 20 - * 30 FF 00 00 00 00 39 00 unknown 0.....9. - * (in a single line of course) - */ - - unsigned char *p = data; - unsigned char c; - int n; - char bytestr[4] = {0}; - char addrstr[10] = {0}; - char hexstr[ 16*3 + 5] = {0}; - char charstr[16*1 + 5] = {0}; - for (n=1;n<=size;n++) { - if (n%16 == 1) { - /* store address for this line */ - snprintf(addrstr, sizeof(addrstr), "%.4x", - ((unsigned int)p-(unsigned int)data) ); - } - - c = *p; - if (isalnum(c) == 0) { - c = '.'; - } - - /* store hex str (for left side) */ - snprintf(bytestr, sizeof(bytestr), "%02X ", *p); - strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1); - - /* store char str (for right side) */ - snprintf(bytestr, sizeof(bytestr), "%c", c); - strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1); - - if (n%16 == 0) { - /* line completed */ - RIL_LOGD("[%4.4s] %-50.50s %s", addrstr, hexstr, charstr); - hexstr[0] = 0; - charstr[0] = 0; - } else if (n%8 == 0) { - /* half line: add whitespaces */ - strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1); - strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1); - } - p++; /* next byte */ - } - - if (strlen(hexstr) > 0) { - /* print rest of buffer if not empty */ - RIL_LOGD("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); - } -} - -/* writes the utf8 character encoded in v - * to the buffer utf8 at the specified offset - */ -int utf8_write(char *utf8, int offset, int v) -{ - - int result; - - if (v < 0x80) { - result = 1; - if (utf8) - utf8[offset] = (char)v; - } else if (v < 0x800) { - result = 2; - if (utf8) { - utf8[offset + 0] = (char)(0xc0 | (v >> 6)); - utf8[offset + 1] = (char)(0x80 | (v & 0x3f)); - } - } else if (v < 0x10000) { - result = 3; - if (utf8) { - utf8[offset + 0] = (char)(0xe0 | (v >> 12)); - utf8[offset + 1] = (char)(0x80 | ((v >> 6) & 0x3f)); - utf8[offset + 2] = (char)(0x80 | (v & 0x3f)); - } - } else { - result = 4; - if (utf8) { - utf8[offset + 0] = (char)(0xf0 | ((v >> 18) & 0x7)); - utf8[offset + 1] = (char)(0x80 | ((v >> 12) & 0x3f)); - utf8[offset + 2] = (char)(0x80 | ((v >> 6) & 0x3f)); - utf8[offset + 3] = (char)(0x80 | (v & 0x3f)); - } - } - return result; -} - -SmsCodingScheme sms_get_coding_scheme(int dataCoding) -{ - switch (dataCoding >> 4) { - case 0x00: - case 0x02: - case 0x03: - return SMS_CODING_SCHEME_GSM7; - case 0x01: - if (dataCoding == 0x10) - return SMS_CODING_SCHEME_GSM7; - if (dataCoding == 0x11) - return SMS_CODING_SCHEME_UCS2; - break; - case 0x04: - case 0x05: - case 0x06: - case 0x07: - if (dataCoding & 0x20) - return SMS_CODING_SCHEME_UNKNOWN; - if (((dataCoding >> 2) & 3) == 0) - return SMS_CODING_SCHEME_GSM7; - if (((dataCoding >> 2) & 3) == 2) - return SMS_CODING_SCHEME_UCS2; - break; - case 0xF: - if (!(dataCoding & 4)) - return SMS_CODING_SCHEME_GSM7; - break; - } - return SMS_CODING_SCHEME_UNKNOWN; -} - -char *pdu_create(char *number, char *message) -{ - unsigned char pdu_first[] = { 0x00, 0x04 }; - unsigned char pdu_toa[] = { 0x91 }; - unsigned char pdu_tp[] = { 0x00, 0x00 }; - unsigned char timestamp[7] = { 0 }; - time_t t; - struct tm *tm; - - unsigned char number_length; - unsigned char message_length; - - unsigned char *buffer = NULL; - char *pdu = NULL; - size_t length = 0; - - unsigned char *p; - unsigned char a; - char c; - int i; - - if (number == NULL || message == NULL || strlen(message) > 0xff) - return NULL; - - number_length = strlen(number) & 0xff; - if (number_length % 2 != 0) - number_length++; - number_length /= 2; - - message_length = ascii2gsm7(message, NULL) & 0xff; - - length = sizeof(pdu_first) + sizeof(number_length) + sizeof(pdu_toa) + number_length + sizeof(pdu_tp) + sizeof(timestamp) + sizeof(message_length) + message_length; - buffer = calloc(1, length); - - p = (unsigned char *) buffer; - - memcpy(p, &pdu_first, sizeof(pdu_first)); - p += sizeof(pdu_first); - - number_length = strlen(number) & 0xff; - - memcpy(p, &number_length, sizeof(number_length)); - p += sizeof(number_length); - memcpy(p, &pdu_toa, sizeof(pdu_toa)); - p += sizeof(pdu_toa); - - i = 0; - while (i < number_length) { - c = number[i++]; - - if (isdigit(c)) - *p = (c - '0') & 0x0f; - - if (i < number_length) { - c = number[i++]; - if (isdigit(c)) - *p |= ((c - '0') & 0x0f) << 4; - } else { - *p |= 0xf << 4; - } - - p++; - } - - memcpy(p, &pdu_tp, sizeof(pdu_tp)); - p += sizeof(pdu_tp); - - t = time(NULL); - tm = localtime(&t); - - a = (tm->tm_year - 100); - timestamp[0] = ((a - (a % 10)) / 10) | ((a % 10) * 0x10); - a = (tm->tm_mon + 1); - timestamp[1] = ((a - (a % 10)) / 10) | ((a % 10) * 0x10); - a = tm->tm_mday; - timestamp[2] = ((a - (a % 10)) / 10) | ((a % 10) * 0x10); - a = tm->tm_hour; - timestamp[3] = ((a - (a % 10)) / 10) | ((a % 10) * 0x10); - a = tm->tm_min; - timestamp[4] = ((a - (a % 10)) / 10) | ((a % 10) * 0x10); - a = tm->tm_sec; - timestamp[5] = ((a - (a % 10)) / 10) | ((a % 10) * 0x10); - a = (unsigned char) (-timezone / 900); - timestamp[6] = ((a - (a % 10)) / 10) | ((a % 10) * 0x10); - - memcpy(p, ×tamp, sizeof(timestamp)); - p += sizeof(timestamp); - - message_length = strlen(message) & 0xff; - - memcpy(p, &message_length, sizeof(message_length)); - p += sizeof(message_length); - - ascii2gsm7(message, p); - p += message_length; - - pdu = (char *) calloc(1, length * 2 + 1); - - bin2hex(buffer, length, pdu); - - free(buffer); - - return pdu; -} @@ -0,0 +1,247 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> + * + * Samsung-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. + * + * Samsung-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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <sys/eventfd.h> + +#define LOG_TAG "RIL" +#include <utils/Log.h> + +#include <samsung-ril.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 data_dump(const void *data, size_t size) +{ + unsigned int cols = 8; + unsigned int cols_count = 2; + int spacer; + char string[81]; + size_t length; + char *print; + unsigned char *p; + unsigned int offset; + unsigned int rollback; + unsigned int i, j, k; + int rc; + + if (data == NULL || size == 0) + return -1; + + // spacer = string length - offset print length - data print length - ascii print length + spacer = (sizeof(string) - 1) - 6 - (3 * cols * cols_count - 1 + (cols_count - 1)) - (cols * cols_count + cols_count - 1); + + // Need 3 spacers + spacer /= 3; + + if (spacer <= 0) + return -1; + + p = (unsigned char *) data; + offset = 0; + + while (offset < size) { + rollback = 0; + + print = (char *) &string; + length = sizeof(string); + + // Offset print + + rc = snprintf(print, length, "[%04x]", offset); + print += rc; + length -= rc; + + // Spacer print + + for (i = 0; i < (unsigned int) spacer; i++) { + *print++ = ' '; + length--; + } + + // Data print + + for (i = 0; i < cols_count; i++) { + for (j = 0; j < cols; j++) { + if (offset < size) { + rc = snprintf(print, length, "%02X", *p); + print += rc; + length -= rc; + + p++; + offset++; + rollback++; + } else { + for (k = 0; k < 2; k++) { + *print++ = ' '; + length--; + } + } + + if (j != (cols - 1)) { + *print++ = ' '; + length--; + } + } + + if (i != (cols_count - 1)) { + for (k = 0; k < 2; k++) { + *print++ = ' '; + length--; + } + } + } + + // Spacer print + + for (i = 0; i < (unsigned int) spacer; i++) { + *print++ = ' '; + length--; + } + + // ASCII print + + p -= rollback; + offset -= rollback; + + for (i = 0; i < cols_count; i++) { + for (j = 0; j < cols; j++) { + if (offset < size) { + if (isascii(*p) && isprint(*p)) + *print = *p; + else + *print = '.'; + + print++; + length--; + + p++; + offset++; + rollback++; + } + } + + if (i != (cols_count - 1) && offset < size) { + *print++ = ' '; + length--; + } + } + + *print = '\0'; + + RIL_LOGD("%s", string); + } + + return 0; +} + +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; +} + +int eventfd_flush(int fd) +{ + eventfd_t flush; + int rc; + + rc = eventfd_read(fd, &flush); + if (rc < 0) + return -1; + + return 0; +} + +int eventfd_recv(int fd, eventfd_t *event) +{ + int rc; + + rc = eventfd_read(fd, event); + if (rc < 0) + return -1; + + return 0; +} + +int eventfd_send(int fd, eventfd_t event) +{ + int rc; + + eventfd_flush(fd); + + rc = eventfd_write(fd, event); + if (rc < 0) + return -1; + + return 0; +} @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,33 +18,25 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _SAMSUNG_RIL_UTIL_H_ -#define _SAMSUNG_RIL_UTIL_H_ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include <stdlib.h> +#include <sys/eventfd.h> struct list_head { struct list_head *prev; struct list_head *next; - void *data; + const void *data; }; -struct list_head *list_head_alloc(void *data, struct list_head *prev, struct list_head *next); +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); - -void bin2hex(const unsigned char *data, int length, char *buf); -void hex2bin(const char *data, int length, unsigned char *buf); -int gsm72ascii(unsigned char *data, char **data_dec, int length); -int ascii2gsm7_ussd(char *data, unsigned char **data_enc, int length); -size_t ascii2gsm7(char *ascii, unsigned char *gsm7); -void hex_dump(void *data, int size); -int utf8_write(char *utf8, int offset, int v); -char *pdu_create(char *number, char *message); - -typedef enum { - SMS_CODING_SCHEME_UNKNOWN = 0, - SMS_CODING_SCHEME_GSM7, - SMS_CODING_SCHEME_UCS2 -} SmsCodingScheme; - -SmsCodingScheme sms_get_coding_scheme(int dataCoding); +int data_dump(const void *data, size_t size); +int strings_array_free(char **array, size_t size); +int eventfd_flush(int fd); +int eventfd_recv(int fd, eventfd_t *event); +int eventfd_send(int fd, eventfd_t event); #endif |