Project

General

Profile

Issue #29 ยป gprs.c

Paul Kocialkowski, 07/15/2012 12:04 PM

 
/**
* This file is part of samsung-ril.
*
* Copyright (C) 2011-2012 Paul Kocialkowski <contact@oaulk.fr>
* Copyright (C) 2011 Denis 'GNUtoo' Carikli <GNUtoo@no-log.org>
*
* samsung-ril is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* samsung-ril is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with samsung-ril. If not, see <http://www.gnu.org/licenses/>.
*
*/

#include <netinet/in.h>
#include <arpa/inet.h>

#define LOG_TAG "RIL-GPRS"
#include <utils/Log.h>
#include <cutils/properties.h>

#include "samsung-ril.h"
#include "util.h"

struct ril_gprs_connection **ril_gprs_connections;
int ril_gprs_connections_count;

RIL_LastDataCallActivateFailCause ipc2ril_gprs_fail_cause(unsigned short fail_cause)
{
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;
}
}

void ril_gprs_connections_init(void)
{
struct ipc_client_gprs_capabilities gprs_capabilities;
struct ipc_client *ipc_client;
int ril_gprs_connections_size = 0;

ipc_client = ((struct ipc_client_object *) ipc_fmt_client->object)->ipc_client;
ipc_client_gprs_get_capabilities(ipc_client, &gprs_capabilities);

ril_gprs_connections_size =
gprs_capabilities.cid_max * sizeof(struct ril_gprs_connection *);

ril_gprs_connections = (struct ril_gprs_connection **)
malloc(ril_gprs_connections_size);
memset((void *) ril_gprs_connections, 0, ril_gprs_connections_size);

ril_gprs_connections_count = gprs_capabilities.cid_max;
}

int ril_gprs_connection_reg_id(void)
{
struct ril_gprs_connection *gprs_connection;
int i;

for(i=0 ; i < ril_gprs_connections_count ; i++) {
if(ril_gprs_connections[i] == NULL)
return i;
}

LOGD("No room left for another GPRS connection, trying to clean one up");

// When all the slots are taken, see if some are in a non-working state
for(i=0 ; i < ril_gprs_connections_count ; i++) {
if(ril_gprs_connections[i]->enabled == 0) {
ril_gprs_connection_del(ril_gprs_connections[i]);

return i;
}
}

return -1;
}

struct ril_gprs_connection *ril_gprs_connection_add(void)
{
struct ril_gprs_connection *gprs_connection = NULL;
int id = ril_gprs_connection_reg_id();

if(id < 0) {
LOGE("Unable to add another GPRS connection!");
return NULL;
}

gprs_connection = malloc(sizeof(struct ril_gprs_connection));
memset(gprs_connection, 0, sizeof(struct ril_gprs_connection));

gprs_connection->cid = id + 1;
gprs_connection->enabled = 0;
gprs_connection->interface = NULL;
gprs_connection->token = (RIL_Token) 0x00;

ril_gprs_connections[id] = gprs_connection;

return gprs_connection;
}

void ril_gprs_connection_del(struct ril_gprs_connection *gprs_connection)
{
int i;

if(gprs_connection == NULL)
return;

if(gprs_connection->interface != NULL)
free(gprs_connection->interface);

for(i=0 ; i < ril_gprs_connections_count ; i++)
if(ril_gprs_connections[i] == gprs_connection)
ril_gprs_connections[i] = NULL;

free(gprs_connection);
}

struct ril_gprs_connection *ril_gprs_connection_get_token(RIL_Token token)
{
int i;

for(i=0 ; i < ril_gprs_connections_count ; i++)
if(ril_gprs_connections[i] != NULL)
if(ril_gprs_connections[i]->token == token)
return ril_gprs_connections[i];

return NULL;
}

struct ril_gprs_connection *ril_gprs_connection_get_cid(int cid)
{
int i;

for(i=0 ; i < ril_gprs_connections_count ; i++)
if(ril_gprs_connections[i] != NULL)
if(ril_gprs_connections[i]->cid == cid)
return ril_gprs_connections[i];

return NULL;
}

void ipc_gprs_pdp_context_enable_complete(struct ipc_message_info *info)
{
struct ipc_gen_phone_res *phone_res = (struct ipc_gen_phone_res *) info->data;
struct ril_gprs_connection *gprs_connection;
int rc;

gprs_connection = ril_gprs_connection_get_token(reqGetToken(info->aseq));

if(!gprs_connection) {
LOGE("Unable to find GPRS connection, aborting");

RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}

rc = ipc_gen_phone_res_check(phone_res);
if(rc < 0) {
LOGE("There was an error, aborting PDP context complete");

gprs_connection->fail_cause = PDP_FAIL_ERROR_UNSPECIFIED;
gprs_connection->token = (RIL_Token) 0x00;
ril_state.gprs_last_failed_cid = gprs_connection->cid;

RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}

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 ipc_gen_phone_res *) info->data;
struct ril_gprs_connection *gprs_connection;
int aseq;
int rc;

gprs_connection = ril_gprs_connection_get_token(reqGetToken(info->aseq));

if(!gprs_connection) {
LOGE("Unable to find GPRS connection, aborting");

RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}

rc = ipc_gen_phone_res_check(phone_res);
if(rc < 0) {
LOGE("There was an error, aborting define PDP context complete");

gprs_connection->fail_cause = PDP_FAIL_ERROR_UNSPECIFIED;
gprs_connection->token = (RIL_Token) 0x00;
ril_state.gprs_last_failed_cid = gprs_connection->cid;

RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}

// We need to get a clean new aseq here
aseq = ril_request_reg_id(reqGetToken(info->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 ipc_gen_phone_res *) info->data;
struct ril_gprs_connection *gprs_connection;
int rc;
int aseq;

gprs_connection = ril_gprs_connection_get_token(reqGetToken(info->aseq));

if(!gprs_connection) {
LOGE("Unable to find GPRS connection, aborting");

RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}

rc = ipc_gen_phone_res_check(phone_res);
if(rc < 0) {
LOGE("There was an error, aborting port list complete");

gprs_connection->fail_cause = PDP_FAIL_ERROR_UNSPECIFIED;
gprs_connection->token = (RIL_Token) 0x00;
ril_state.gprs_last_failed_cid = gprs_connection->cid;

RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}

// We need to get a clean new aseq here
aseq = ril_request_reg_id(reqGetToken(info->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;

ipc_client = ((struct ipc_client_object *) ipc_fmt_client->object)->ipc_client;

apn = ((char **) data)[2];
username = ((char **) data)[3];
password = ((char **) data)[4];

LOGD("Requesting data connection to APN '%s'\n", apn);

gprs_connection = ril_gprs_connection_add();

if(!gprs_connection) {
LOGE("Unable to create GPRS connection, aborting");

RIL_onRequestComplete(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(reqGetId(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), reqGetId(t));
} else {
ipc_gen_phone_res_expect_to_func(reqGetId(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), reqGetId(t));
}
}

void ipc_gprs_ip_configuration(struct ipc_message_info *info)
{
struct ril_gprs_connection *gprs_connection;
struct ipc_gprs_ip_configuration *ip_configuration =
(struct ipc_gprs_ip_configuration *) info->data;

gprs_connection = ril_gprs_connection_get_cid(ip_configuration->cid);

if(!gprs_connection) {
LOGE("Unable to find GPRS connection, aborting");

RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}

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));

LOGD("Waiting for GPRS call status");
}

void ipc_gprs_pdp_context_disable_complete(struct ipc_message_info *info)
{
struct ipc_gen_phone_res *phone_res = (struct ipc_gen_phone_res *) info->data;
struct ril_gprs_connection *gprs_connection;
int rc;

gprs_connection = ril_gprs_connection_get_token(reqGetToken(info->aseq));

if(!gprs_connection) {
LOGE("Unable to find GPRS connection, aborting");

RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}

rc = ipc_gen_phone_res_check(phone_res);
if(rc < 0) {
LOGE("There was an error, aborting PDP context complete");

// RILJ is not going to ask for fail reason
ril_gprs_connection_del(gprs_connection);

RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}

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 = ((char **) data)[0];
int rc;

gprs_connection = ril_gprs_connection_get_cid(atoi(cid));

if(!gprs_connection) {
LOGE("Unable to find GPRS connection, aborting");

RIL_onRequestComplete(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(reqGetId(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), reqGetId(t));
}

int ipc_gprs_connection_enable(struct ril_gprs_connection *gprs_connection, char **setup_data_call_response)
{
struct ipc_client *ipc_client;
struct ipc_gprs_ip_configuration *ip_configuration;

char *interface = NULL;
char *ip;
char *gateway;
char *subnet_mask;
char *dns1;
char *dns2;

char prop_name[PROPERTY_KEY_MAX];

int rc;

ipc_client = ((struct ipc_client_object *) ipc_fmt_client->object)->ipc_client;

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]);

if(ipc_client_gprs_handlers_available(ipc_client)) {
rc = ipc_client_gprs_activate(ipc_client);
if(rc < 0) {
// This is not a critical issue
LOGE("Failed to activate interface!");
}
}

rc = ipc_client_gprs_get_iface(ipc_client, &interface, gprs_connection->cid);
if(rc < 0) {
// This is not a critical issue, fallback to rmnet
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);
}

LOGD("Using net interface: %s\n", interface);

LOGD("GPRS configuration: iface: %s, ip:%s, gateway:%s, subnet_mask:%s, dns1:%s, dns2:%s",
interface, ip, gateway, subnet_mask, dns1, dns2);

rc = ifc_configure(interface, inet_addr(ip),
inet_addr(subnet_mask), inet_addr(gateway),
inet_addr(dns1), inet_addr(dns2));

if(rc < 0) {
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);

asprintf(&(setup_data_call_response[0]), "%d", gprs_connection->cid);
setup_data_call_response[1] = interface;
setup_data_call_response[2] = ip;

free(gateway);
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;

ipc_client = ((struct ipc_client_object *) ipc_fmt_client->object)->ipc_client;

if(gprs_connection->interface == NULL) {
rc = ipc_client_gprs_get_iface(ipc_client, &interface, gprs_connection->cid);
if(rc < 0) {
// This is not a critical issue, fallback to rmnet
LOGE("Failed to get interface name!");
asprintf(&interface, "rmnet%d", gprs_connection->cid);
}
} else {
interface = gprs_connection->interface;
}

LOGD("Using net interface: %s\n", interface);

rc = ifc_down(interface);

if(gprs_connection->interface == NULL)
free(interface);

if(rc < 0) {
LOGE("ifc_down failed");
}

if(ipc_client_gprs_handlers_available(ipc_client)) {
rc = ipc_client_gprs_deactivate(ipc_client);
if(rc < 0) {
// This is not a critical issue
LOGE("Failed to deactivate interface!");
}
}

return 0;
}

void ipc_gprs_call_status(struct ipc_message_info *info)
{
struct ril_gprs_connection *gprs_connection;
struct ipc_gprs_call_status *call_status =
(struct ipc_gprs_call_status *) info->data;

char *setup_data_call_response[3] = { NULL, NULL, NULL };
int rc;

gprs_connection = ril_gprs_connection_get_cid(call_status->cid);

if(!gprs_connection) {
LOGE("Unable to find GPRS connection, aborting");

RIL_onRequestComplete(reqGetToken(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) 0x00) {
LOGD("GPRS connection is now enabled");

rc = ipc_gprs_connection_enable(gprs_connection, setup_data_call_response);
if(rc < 0) {
LOGE("Failed to enable and configure GPRS interface");

gprs_connection->enabled = 0;
gprs_connection->fail_cause = PDP_FAIL_ERROR_UNSPECIFIED;
ril_state.gprs_last_failed_cid = gprs_connection->cid;

RIL_onRequestComplete(gprs_connection->token, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
LOGD("GPRS interface enabled");

gprs_connection->enabled = 1;

RIL_onRequestComplete(gprs_connection->token, RIL_E_SUCCESS, setup_data_call_response, sizeof(setup_data_call_response));
gprs_connection->token = (RIL_Token) 0x00;
}

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]);
} else if(gprs_connection->enabled &&
call_status->state == IPC_GPRS_STATE_DISABLED &&
gprs_connection->token != (RIL_Token) 0x00) {
LOGD("GPRS connection is now disabled");

rc = ipc_gprs_connection_disable(gprs_connection);
if(rc < 0) {
LOGE("Failed to disable GPRS interface");

RIL_onRequestComplete(gprs_connection->token, RIL_E_GENERIC_FAILURE, NULL, 0);

// RILJ is not going to ask for fail reason
ril_gprs_connection_del(gprs_connection);
} else {
LOGD("GPRS interface disabled");

gprs_connection->enabled = 0;

RIL_onRequestComplete(gprs_connection->token, RIL_E_SUCCESS, NULL, 0);

ril_gprs_connection_del(gprs_connection);
}
} else {
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, 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) 0x00) {
LOGE("Failed to enable GPRS connection");

gprs_connection->enabled = 0;
gprs_connection->fail_cause = ipc2ril_gprs_fail_cause(call_status->fail_cause);
ril_state.gprs_last_failed_cid = gprs_connection->cid;

RIL_onRequestComplete(gprs_connection->token, RIL_E_GENERIC_FAILURE, NULL, 0);
gprs_connection->token = (RIL_Token) 0x00;

ril_unsol_data_call_list_changed();
} else if(gprs_connection->enabled &&
call_status->state == IPC_GPRS_STATE_DISABLED) {
LOGE("GPRS connection suddently got disabled");

rc = ipc_gprs_connection_disable(gprs_connection);
if(rc < 0) {
LOGE("Failed to disable GPRS interface");

// RILJ is not going to ask for fail reason
ril_gprs_connection_del(gprs_connection);
} else {
LOGE("GPRS interface disabled");

gprs_connection->enabled = 0;
ril_gprs_connection_del(gprs_connection);
}

ril_unsol_data_call_list_changed();
} else {
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, gprs_connection->token);

ril_unsol_data_call_list_changed();
}
}
}

void ril_request_last_data_call_fail_cause(RIL_Token t)
{
struct ril_gprs_connection *gprs_connection;
int last_failed_cid;
int fail_cause;

last_failed_cid = ril_state.gprs_last_failed_cid;

if(!last_failed_cid) {
LOGE("No GPRS connection was reported to have failed");

goto fail_cause_unspecified;
}

gprs_connection = ril_gprs_connection_get_cid(last_failed_cid);

if(!gprs_connection) {
LOGE("Unable to find GPRS connection");

goto fail_cause_unspecified;
}

fail_cause = gprs_connection->fail_cause;

LOGD("Destroying GPRS connection with cid: %d", gprs_connection->cid);
ril_gprs_connection_del(gprs_connection);

goto fail_cause_return;

fail_cause_unspecified:
fail_cause = PDP_FAIL_ERROR_UNSPECIFIED;

fail_cause_return:
ril_state.gprs_last_failed_cid = 0;
RIL_onRequestComplete(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.
*/
void ipc_gprs_pdp_context_fix(RIL_Data_Call_Response *data_call_list, int c)
{
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 =
(struct ipc_gprs_pdp_context_get *) info->data;

RIL_Data_Call_Response data_call_list[IPC_GPRS_PDP_CONTEXT_GET_DESC_COUNT];

int i;

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_get_cid(context->desc[i].cid);

if(gprs_connection == NULL) {
LOGE("CID %d reported as enabled but not listed here");
goto empty;
}

ip_configuration = &(gprs_connection->ip_configuration);

asprintf(&(data_call_list[i].type), "IP");
asprintf(&(data_call_list[i].apn), "%s",
gprs_connection->define_context.apn);
asprintf(&(data_call_list[i].address), "%i.%i.%i.%i",
(ip_configuration->ip)[0],(ip_configuration->ip)[1], (ip_configuration->ip)[2],(ip_configuration->ip)[3]);

continue;
}

empty:
data_call_list[i].type = NULL;
data_call_list[i].apn = NULL;
data_call_list[i].address = NULL;
}

ipc_gprs_pdp_context_fix(data_call_list, IPC_GPRS_PDP_CONTEXT_GET_DESC_COUNT);

if(info->aseq == 0xff)
RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED, &data_call_list, sizeof(data_call_list));
else
RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_SUCCESS, &data_call_list, sizeof(data_call_list));

for(i=0 ; i < IPC_GPRS_PDP_CONTEXT_GET_DESC_COUNT ; i++) {
if(data_call_list[i].type != NULL)
free(data_call_list[i].type);
if(data_call_list[i].apn != NULL)
free(data_call_list[i].apn);
if(data_call_list[i].address != NULL)
free(data_call_list[i].address);
}
}

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)
{
ipc_fmt_send_get(IPC_GPRS_PDP_CONTEXT, reqGetId(t));
}
    (1-1/1)