From a7ff1df1869ce543171a6ee92cbf821647b1bf7d Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 7 Aug 2014 13:12:15 +0200 Subject: Samsung-RIL rewrite: harder, better, probably not faster but definitely stronger Signed-off-by: Paul Kocialkowski --- Android.mk | 44 +- call.c | 683 +++++++++++---- client.c | 243 ++++-- data.c | 1049 ++++++++++++++++++++++ disp.c | 160 ---- gen.c | 275 ++++-- gprs.c | 1075 ----------------------- include/plmn_list.h | 611 ++++++++----- include/plmn_list.sh | 31 +- include/ril_oem.h | 52 ++ include/samsung-ril-socket.h | 84 +- include/sim.h | 60 +- ipc.c | 1106 ++++++++++++++++++++---- ipc.h | 110 ++- misc.c | 362 ++++---- net.c | 916 -------------------- network.c | 1168 +++++++++++++++++++++++++ oem.c | 238 +++++ power.c | 117 +++ pwr.c | 110 --- rfs.c | 148 ++-- samsung-ril.c | 1826 +++++++++++++++++++++++++++------------ samsung-ril.h | 716 +++++++-------- sat.c | 166 ---- sec.c | 981 --------------------- sim.c | 1303 ++++++++++++++++++++++++++++ sms.c | 1041 ++++++++-------------- snd.c | 132 --- sound.c | 159 ++++ srs-client/include/srs-client.h | 47 +- srs-client/srs-client.c | 551 +++++++----- srs.c | 1181 ++++++++++++++++++------- srs.h | 95 +- ss.c | 251 ------ svc.c | 244 ------ util.c | 486 ----------- util.h | 50 -- utils.c | 247 ++++++ utils.h | 42 + 39 files changed, 10353 insertions(+), 7807 deletions(-) create mode 100644 data.c delete mode 100644 disp.c delete mode 100644 gprs.c create mode 100644 include/ril_oem.h delete mode 100644 net.c create mode 100644 network.c create mode 100644 oem.c create mode 100644 power.c delete mode 100644 pwr.c delete mode 100644 sat.c delete mode 100644 sec.c create mode 100644 sim.c delete mode 100644 snd.c create mode 100644 sound.c delete mode 100644 ss.c delete mode 100644 svc.c delete mode 100644 util.c delete mode 100644 util.h create mode 100644 utils.c create mode 100644 utils.h diff --git a/Android.mk b/Android.mk index 08b4f48..29f0c24 100644 --- a/Android.mk +++ b/Android.mk @@ -1,7 +1,7 @@ # This file is part of Samsung-RIL. # # Copyright (C) 2010-2011 Joerie de Gram -# Copyright (C) 2011-2013 Paul Kocialkowski +# Copyright (C) 2011-2014 Paul Kocialkowski # # 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 diff --git a/call.c b/call.c index 680aba5..6a3ffb9 100644 --- a/call.c +++ b/call.c @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ -#define LOG_TAG "RIL-CALL" +#include + +#define LOG_TAG "RIL" #include -#include "samsung-ril.h" +#include 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; } diff --git a/client.c b/client.c index 92ebc2c..1e06554 100644 --- a/client.c +++ b/client.c @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ +#include #include #define LOG_TAG "RIL" #include -#include "samsung-ril.h" +#include -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; } diff --git a/data.c b/data.c new file mode 100644 index 0000000..1aa69d1 --- /dev/null +++ b/data.c @@ -0,0 +1,1049 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2011-2014 Paul Kocialkowski + * Copyright (C) 2011 Denis 'GNUtoo' Carikli + * + * 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 . + */ + +#include +#include + +#define LOG_TAG "RIL" +#include +#include + +#include +#include + +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; +} diff --git a/disp.c b/disp.c deleted file mode 100644 index 9f6a56a..0000000 --- a/disp.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski - * - * 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 . - */ - -#define LOG_TAG "RIL-DISP" -#include - -#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)); -} diff --git a/gen.c b/gen.c index 596560c..8bfdb13 100644 --- a/gen.c +++ b/gen.c @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ -#define LOG_TAG "RIL-GEN" -#include +#include -#include "samsung-ril.h" -#include "util.h" +#define LOG_TAG "RIL" +#include -/* - * 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 +#include -/* - * 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; } diff --git a/gprs.c b/gprs.c deleted file mode 100644 index 90dda72..0000000 --- a/gprs.c +++ /dev/null @@ -1,1075 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2011-2013 Paul Kocialkowski - * Copyright (C) 2011 Denis 'GNUtoo' Carikli - * - * 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 . - */ - -#include -#include - -#define LOG_TAG "RIL-GPRS" -#include -#include - -#if RIL_VERSION >= 6 -#include -#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 + 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 " +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|.*]*>\(.*\).*|\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|.*]*>\(.*\).*|\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 + * + * 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 . + */ + +#ifndef _RIL_OEM_H_ +#define _RIL_OEM_H_ + +#include + +#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 + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ -/* 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 -#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 + * Copyright (C) 2013-2014 Paul Kocialkowski * * 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 -#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 diff --git a/ipc.c b/ipc.c index a86a27f..d8601fa 100644 --- a/ipc.c +++ b/ipc.c @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ +#include +#include + #define LOG_TAG "RIL-IPC" #include +#include -#include "samsung-ril.h" +#include +#include /* - * 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, }; diff --git a/ipc.h b/ipc.h index 3ede416..3874b76 100644 --- a/ipc.h +++ b/ipc.h @@ -1,8 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 -#define ipc_fmt_send_get(command, mseq) \ - ipc_fmt_send(command, IPC_TYPE_GET, NULL, 0, mseq) +#include -#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 diff --git a/misc.c b/misc.c index 131a660..7668022 100644 --- a/misc.c +++ b/misc.c @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ -#define LOG_TAG "RIL-MISC" +#include + +#define LOG_TAG "RIL" #include -#include "samsung-ril.h" -#include "util.h" +#include -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; } diff --git a/net.c b/net.c deleted file mode 100644 index 04a06ff..0000000 --- a/net.c +++ /dev/null @@ -1,916 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski - * - * 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 . - */ - -#define LOG_TAG "RIL-NET" -#include - -#include "samsung-ril.h" -#include "util.h" - -#include - -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 + * Copyright (C) 2011-2014 Paul Kocialkowski + * + * 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 . + */ + +#include +#include + +#define LOG_TAG "RIL" +#include + +#include +#include +#include + +#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; +} diff --git a/oem.c b/oem.c new file mode 100644 index 0000000..a5781c0 --- /dev/null +++ b/oem.c @@ -0,0 +1,238 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2013-2014 Paul Kocialkowski + * + * 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 . + */ + +#include + +#define LOG_TAG "RIL" +#include + +#include +#include + +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; +} diff --git a/power.c b/power.c new file mode 100644 index 0000000..6de7eb0 --- /dev/null +++ b/power.c @@ -0,0 +1,117 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2010-2011 Joerie de Gram + * Copyright (C) 2011-2014 Paul Kocialkowski + * + * 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 . + */ + +#include + +#define LOG_TAG "RIL" +#include + +#include +#include + +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; +} diff --git a/pwr.c b/pwr.c deleted file mode 100644 index e6c4eb4..0000000 --- a/pwr.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski - * - * 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 . - */ - -#define LOG_TAG "RIL-PWR" -#include - -#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; - } -} diff --git a/rfs.c b/rfs.c index da2a77e..74d5325 100644 --- a/rfs.c +++ b/rfs.c @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ +#include + #define LOG_TAG "RIL-RFS" #include -#include "samsung-ril.h" -#include "util.h" +#include +#include -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 - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ +#include +#include + #define LOG_TAG "RIL" -#include "samsung-ril.h" -#include "util.h" +#include +#include + +#include +#include /* * 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; + } - while (ril_data.request_id < id) { - ril_data.request_id++; - ril_data.request_id %= 0xff; + count++; + +list_continue: + list = list->next; + } + + RIL_LOGD("%d RIL request%s in the queue (%d pending, %d handled, %d unhandled)", count, count > 1 ? "s" : "", pending, handled, unhandled); + + count = 0; + + list = ril_data->requests_data; + while (list != NULL) { + count++; + + list = list->next; } - 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; + + if (size > 0) { + ril_request->data = calloc(1, size); + memcpy(ril_request->data, data, size); + } - list_end = ril_data.requests; + 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; + + ril_client_request_register(ril_clients[i], request, token); + } - if (ril_data.requests == NULL) - ril_data.requests = list; + 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; - list = ril_data.requests; + 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; 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; +} + +int ril_request_flush(void) +{ + struct ril_request *request; + struct list_head *list; + struct list_head *list_next; + + if (ril_data == NULL) + return -1; + + RIL_REQUEST_LOCK(); + + list = ril_data->requests; + while (list != NULL) { + if (list->data != NULL) { + request = (struct ril_request *) list->data; + + if (request->data != NULL && request->size > 0) + free(request->data); + + memset(request, 0, sizeof(struct ril_request)); + free(request); + } + + if (list == ril_data->requests) + ril_data->requests = list->next; + + list_next = list->next; + + list_head_free(list); + +list_continue: + list = list_next; + } + + RIL_REQUEST_UNLOCK(); + + return 0; } -struct ril_request_info *ril_request_info_find_id(int id) +struct ril_request *ril_request_find(void) { - struct ril_request_info *request; + struct ril_request *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->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; + } - return request->canceled; +list_continue: + list = list->next; + } + + RIL_REQUEST_UNLOCK(); + + 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; + } + + RIL_REQUEST_UNLOCK(); - return request->token; + 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; - - ril_request_unsolicited(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); + struct ril_request *request; + int rc; - ril_tokens_check(); -} + if (ril_data == NULL) + return NULL; -/* - * RIL tokens - */ + while (1) { + RIL_REQUEST_LOOP_LOCK(); -void ril_tokens_check(void) -{ - RIL_Token t; + RIL_LOCK(); - 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); + rc = ril_radio_state_check(RADIO_STATE_OFF); + if (rc < 0) { + RIL_UNLOCK(); + continue; } - } - 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); - } + 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; } /* - * Clients dispatch functions + * RIL request data */ -void ipc_fmt_dispatch(struct ipc_message_info *info) +int ril_request_data_register(int request, void *data, size_t size) { - if (info == NULL) - return; + struct ril_request_data *request_data; + struct list_head *list_end; + struct list_head *list; + unsigned int i; - RIL_LOCK(); + if (data == NULL || ril_data == NULL) + return -1; - ril_request_id_set(info->aseq); + 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; - 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); - break; - default: - RIL_LOGE("%s: Unhandled request: %s (%04x)", __func__, ipc_command_to_str(IPC_COMMAND(info)), IPC_COMMAND(info)); - break; - } + list_end = ril_data->requests_data; + while (list_end != NULL && list_end->next != NULL) + list_end = list_end->next; - RIL_UNLOCK(); + list = list_head_alloc(list_end, NULL, (void *) request_data); + + if (ril_data->requests_data == NULL) + ril_data->requests_data = list; + + return 0; } -void ipc_rfs_dispatch(struct ipc_message_info *info) +int ril_request_data_unregister(struct ril_request_data *request_data) { - if (info == NULL) - return; + struct list_head *list; + unsigned int i; - RIL_LOCK(); + if (request_data == NULL || ril_data == NULL) + return -1; - 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); - break; - default: - RIL_LOGE("%s: Unhandled request: %s (%04x)", __func__, ipc_command_to_str(IPC_COMMAND(info)), IPC_COMMAND(info)); - break; + 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; } - RIL_UNLOCK(); + return 0; } -void srs_dispatch(struct srs_message *message) +int ril_request_data_flush(void) { - if (message == NULL) - return; + struct ril_request_data *request_data; + struct list_head *list; + struct list_head *list_next; - RIL_LOCK(); + if (ril_data == NULL) + return -1; - 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); + 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; - case SRS_SND_SET_CALL_AUDIO_PATH: - srs_snd_set_call_audio_path(message); + + if (request_data->data != NULL && request_data->size > 0) + free(request_data->data); + + ril_request_data_unregister(request_data); + } while (request_data != NULL); + + return 0; +} + +int ril_request_data_set(int request, void *data, size_t size) +{ + void *buffer; + int rc; + + if (data == NULL || size == 0) + return -1; + + buffer = calloc(1, size); + memcpy(buffer, data, size); + + rc = ril_request_data_register(request, buffer, size); + if (rc < 0) + return -1; + + return 0; +} + +int ril_request_data_set_uniq(int request, void *data, size_t size) +{ + int rc; + + ril_request_data_free(request); + + rc = ril_request_data_set(request, data, size); + if (rc < 0) + return -1; + + return 0; +} + +size_t ril_request_data_size_get(int request) +{ + struct ril_request_data *request_data; + + request_data = ril_request_data_find_request(request); + if (request_data == NULL) + return 0; + + return request_data->size; +} + +void *ril_request_data_get(int request) +{ + struct ril_request_data *request_data; + void *buffer; + + request_data = ril_request_data_find_request(request); + if (request_data == NULL) + return NULL; + + buffer = request_data->data; + + ril_request_data_unregister(request_data); + + return buffer; +} + +/* + * RIL radio state + */ + +int ril_radio_state_update(RIL_RadioState radio_state) +{ + struct ril_request *request; + unsigned int i; + int rc; + + if (ril_data == NULL) + return -1; + + if (ril_data->radio_state == radio_state) + return 0; + + RIL_LOGD("Updating RIL radio state to %d", radio_state); + + ril_data->radio_state = radio_state; + ril_request_unsolicited(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); + + switch (ril_data->radio_state) { + case RADIO_STATE_UNAVAILABLE: + do { + request = ril_request_find(); + if (request == NULL) + break; + + ril_request_complete(request->token, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0); + + ril_request_unregister(request); + } while (request != NULL); + + ril_request_flush(); + ril_request_data_flush(); + + ril_request_stats_log(); + + 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: (%04x)", __func__, message->command); + RIL_REQUEST_LOOP_UNLOCK(); break; } - RIL_UNLOCK(); + return 0; +} + +int ril_radio_state_check(RIL_RadioState radio_state) +{ + RIL_RadioState radio_states[] = { + RADIO_STATE_UNAVAILABLE, + RADIO_STATE_OFF, + RADIO_STATE_ON, + RADIO_STATE_NV_NOT_READY, + RADIO_STATE_NV_READY, + RADIO_STATE_SIM_NOT_READY, + RADIO_STATE_SIM_LOCKED_OR_ABSENT, + RADIO_STATE_SIM_READY, + }; + unsigned int index; + unsigned int count; + unsigned int i; + + if (ril_data == NULL) + return -1; + + count = sizeof(radio_states) / sizeof(RIL_RadioState); + + for (i = 0; i < count; i++) + if (radio_states[i] == radio_state) + break; + + index = i; + + for (i = 0; i < count; i++) + if (radio_states[i] == ril_data->radio_state) + break; + + if (i < index) + return -1; + + return 0; +} + +/* + * RIL data + */ + +int ril_data_create(void) +{ + ril_data = (struct ril_data *) calloc(1, sizeof(struct ril_data)); + + pthread_mutex_init(&ril_data->mutex, NULL); + pthread_mutex_init(&ril_data->request_mutex, NULL); + pthread_mutex_init(&ril_data->request_loop_mutex, NULL); + + RIL_REQUEST_LOOP_LOCK(); + + 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; + } + + ril_request_unregister(request); - pthread_mutex_init(&ril_data.mutex, NULL); + ril_request_stats_log(); - ril_data.state.radio_state = RADIO_STATE_UNAVAILABLE; + 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 - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 +#include #include #include -#include #include #include +#include -#include "ipc.h" -#include "srs.h" +#include +#include +#include /* - * 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 diff --git a/sat.c b/sat.c deleted file mode 100644 index d05e674..0000000 --- a/sat.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski - * - * 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 . - */ - -#define LOG_TAG "RIL-SAT" -#include - -#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); -} - diff --git a/sec.c b/sec.c deleted file mode 100644 index 7d92f26..0000000 --- a/sec.c +++ /dev/null @@ -1,981 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski - * - * 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 . - */ - -#define LOG_TAG "RIL-SEC" -#include - -#include "samsung-ril.h" -#include "util.h" - -#include - -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); -} diff --git a/sim.c b/sim.c new file mode 100644 index 0000000..3d940fa --- /dev/null +++ b/sim.c @@ -0,0 +1,1303 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2010-2011 Joerie de Gram + * Copyright (C) 2011-2014 Paul Kocialkowski + * + * 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 . + */ + +#include + +#define LOG_TAG "RIL" +#include + +#include +#include +#include + +#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; +} diff --git a/sms.c b/sms.c index 2b990e3..6f8a8f8 100644 --- a/sms.c +++ b/sms.c @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ -#define LOG_TAG "RIL-SMS" +#include + +#define LOG_TAG "RIL" #include -#include "samsung-ril.h" -#include "util.h" +#include +#include -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; } diff --git a/snd.c b/snd.c deleted file mode 100644 index f71da7f..0000000 --- a/snd.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2011-2013 Paul Kocialkowski - * - * 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 . - */ - -#define LOG_TAG "RIL-SND" -#include - -#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()); -} diff --git a/sound.c b/sound.c new file mode 100644 index 0000000..22601b3 --- /dev/null +++ b/sound.c @@ -0,0 +1,159 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2011-2014 Paul Kocialkowski + * + * 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 . + */ + +#include + +#define LOG_TAG "RIL" +#include + +#include + +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 + * Copyright (C) 2013-2014 Paul Kocialkowski * * 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 . */ -#include - -#include - #ifndef _SRS_CLIENT_H_ #define _SRS_CLIENT_H_ -#define SRS_CLIENT_TIMEOUT 500000 +#include +#include -#define SRS_CLIENT_LOCK(client) pthread_mutex_lock(&(client->mutex)) -#define SRS_CLIENT_UNLOCK(client) pthread_mutex_unlock(&(client->mutex)) +#include -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 + * Copyright (C) 2013-2014 Paul Kocialkowski * * 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 #include #include +#include #include #include @@ -39,120 +40,254 @@ #include /* - * 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; } diff --git a/srs.c b/srs.c index b05beb3..890a33e 100644 --- a/srs.c +++ b/srs.c @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 . */ +#include +#include #include #include #include #include #include #include +#include #include #include @@ -30,52 +33,213 @@ #define LOG_TAG "RIL-SRS" #include +#include -#include "samsung-ril.h" -#include "util.h" +#include +#include -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, }; diff --git a/srs.h b/srs.h index 873d764..5dfb4f3 100644 --- a/srs.h +++ b/srs.h @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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 -#include -#include -#include +#include -#include -#include +#include -#include +/* + * 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 diff --git a/ss.c b/ss.c deleted file mode 100644 index bad8958..0000000 --- a/ss.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2013 Paul Kocialkowski - * - * 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 . - */ - -#define LOG_TAG "RIL-SS" -#include - -#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); -} diff --git a/svc.c b/svc.c deleted file mode 100644 index ed90232..0000000 --- a/svc.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2013 Paul Kocialkowski - * - * 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 . - */ - -#define LOG_TAG "RIL-SVC" -#include - -#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); -} diff --git a/util.c b/util.c deleted file mode 100644 index 5d73d2c..0000000 --- a/util.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski - * - * 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 . - */ - -#include -#include -#include -#include - -#define LOG_TAG "RIL-UTIL" -#include -#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; -} diff --git a/util.h b/util.h deleted file mode 100644 index b962e46..0000000 --- a/util.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of Samsung-RIL. - * - * Copyright (C) 2010-2011 Joerie de Gram - * Copyright (C) 2011-2013 Paul Kocialkowski - * - * 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 . - */ - -#ifndef _SAMSUNG_RIL_UTIL_H_ -#define _SAMSUNG_RIL_UTIL_H_ - -struct list_head { - struct list_head *prev; - struct list_head *next; - void *data; -}; - -struct list_head *list_head_alloc(void *data, struct list_head *prev, struct list_head *next); -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); - -#endif diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..164812e --- /dev/null +++ b/utils.c @@ -0,0 +1,247 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2010-2011 Joerie de Gram + * Copyright (C) 2011-2014 Paul Kocialkowski + * + * 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 . + */ + +#include +#include +#include +#include + +#define LOG_TAG "RIL" +#include + +#include +#include + +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; +} diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..f651d35 --- /dev/null +++ b/utils.h @@ -0,0 +1,42 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2010-2011 Joerie de Gram + * Copyright (C) 2011-2014 Paul Kocialkowski + * + * 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 . + */ + +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include +#include + +struct list_head { + struct list_head *prev; + struct list_head *next; + const void *data; +}; + +struct list_head *list_head_alloc(struct list_head *prev, struct list_head *next, + const void *data); +void list_head_free(struct list_head *list); +int 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 -- cgit v1.1