summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kocialkowski <contact@paulk.fr>2012-07-08 00:43:47 +0200
committerPaul Kocialkowski <contact@paulk.fr>2012-07-08 00:43:47 +0200
commit7fc060a1d6ba6e3fddcca3ffeccaf25c94de55f7 (patch)
treeeb986b5285e4d6510f3c5d81f275bed016c41941
parent72a86665de9e8283539d6003dc1c64d16237d869 (diff)
downloadhardware_ril_samsung-ril-7fc060a1d6ba6e3fddcca3ffeccaf25c94de55f7.zip
hardware_ril_samsung-ril-7fc060a1d6ba6e3fddcca3ffeccaf25c94de55f7.tar.gz
hardware_ril_samsung-ril-7fc060a1d6ba6e3fddcca3ffeccaf25c94de55f7.tar.bz2
GPRS: Improved stability with status, fail cause and per-cid handling
* GPRS call status handling (state and fail cause) * Last call fail cause reporting * Data call list reporting * Take GPRS call status in account before reporting connection change * Per-cid GPRS connection handling Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
-rw-r--r--gprs.c737
-rw-r--r--samsung-ril.c19
-rw-r--r--samsung-ril.h24
3 files changed, 651 insertions, 129 deletions
diff --git a/gprs.c b/gprs.c
index 276c001..b0b872a 100644
--- a/gprs.c
+++ b/gprs.c
@@ -29,91 +29,263 @@
#include "samsung-ril.h"
#include "util.h"
-/* FIXME: we don't want these hardcoded */
-#define IP_STRING_SIZE 15 + 1
-
-// libnetutils missing prototype
-extern int ifc_configure(const char *ifname,
- in_addr_t address,
- in_addr_t netmask,
- in_addr_t gateway,
- in_addr_t dns1,
- in_addr_t dns2);
-
-void ipc_gprs_pdp_context_complete(struct ipc_message_info *info)
+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->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;
+
+ 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");
- // TODO: Fill last fail reason!
- ril_state.tokens.gprs_context = (RIL_Token) 0x00;
+ 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;
- int rc;
+ 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");
- // TODO: Fill last fail reason!
- ril_state.tokens.gprs_context = (RIL_Token) 0x00;
+ 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 */
+ // 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_complete);
-
- /* activate the connection */
- ipc_fmt_send(IPC_GPRS_PDP_CONTEXT, IPC_TYPE_SET,
- (void *) &(ril_state.gprs_context), sizeof(struct ipc_gprs_pdp_context), aseq);
+ ipc_gprs_pdp_context_enable_complete);
- // TODO: if this aborts, last fail cause will be: PDP_FAIL_ERROR_UNSPECIFIED
+ 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");
- // TODO: Fill last fail reason!
- ril_state.tokens.gprs_context = (RIL_Token) 0x00;
+ 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 */
+ // 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);
- /* send the struct to the modem */
- ipc_fmt_send(IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET,
- (void *) &(ril_state.gprs_define_context), sizeof(struct ipc_gprs_define_pdp_context), aseq);
+ 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;
@@ -124,106 +296,178 @@ void ril_request_setup_data_call(RIL_Token t, void *data, int length)
ipc_client = ((struct ipc_client_object *) ipc_fmt_client->object)->ipc_client;
- /* get the apn, username and password */
apn = ((char **) data)[2];
username = ((char **) data)[3];
-
- if(username != NULL) {
- if(strlen(username) < 2)
- username = "dummy";
- } else {
- username = "dummy";
- }
-
password = ((char **) data)[4];
- if(password != NULL) {
- if(strlen(password) < 2)
- password = "dummy";
- } else {
- password = "dummy";
- }
-
LOGD("Requesting data connection to APN '%s'\n", apn);
- if(ril_state.tokens.gprs_context != (RIL_Token) 0x00) {
- LOGE("There is already a data call request going on!");
- // TODO: Fill last fail reason!
+ gprs_connection = ril_gprs_connection_add();
+
+ if(!gprs_connection) {
+ LOGE("Unable to create GPRS connection, aborting");
- ril_state.tokens.gprs_context = (RIL_Token) 0x00;
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
return;
}
- ril_state.tokens.gprs_context = t;
+ gprs_connection->token = t;
- /* create the structs with the apn */
- ipc_gprs_define_pdp_context_setup(&(ril_state.gprs_define_context), apn);
+ // 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(&(ril_state.gprs_context), 1, username, password);
+ // 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 handlers are available, deal with port list
+ // 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,
+ 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);
- /* send the struct to the modem */
- ipc_fmt_send(IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET,
- (void *) &(ril_state.gprs_define_context), sizeof(struct ipc_gprs_define_pdp_context), reqGetId(t));
+ 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)
{
- /* Quick and dirty configuration, TODO: Handle that better */
+ struct ril_gprs_connection *gprs_connection;
+ struct ipc_gprs_ip_configuration *ip_configuration =
+ (struct ipc_gprs_ip_configuration *) info->data;
- struct ipc_gprs_ip_configuration *ip_config = (struct ipc_gprs_ip_configuration *) info->data;
- struct ipc_client *ipc_client;
+ gprs_connection = ril_gprs_connection_get_cid(ip_configuration->cid);
- char local_ip[IP_STRING_SIZE];
- char gateway[IP_STRING_SIZE];
- char subnet_mask[IP_STRING_SIZE];
- char dns1[IP_STRING_SIZE];
- char dns2[IP_STRING_SIZE];
+ if(!gprs_connection) {
+ LOGE("Unable to find GPRS connection, aborting");
- char dns_prop_name[PROPERTY_KEY_MAX];
- char gw_prop_name[PROPERTY_KEY_MAX];
+ RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
- char *interface;
+ LOGD("Obtained IP Configuration");
- char *response[3];
+ // 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;
- ipc_client = ((struct ipc_client_object *) ipc_fmt_client->object)->ipc_client;
+ 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;
+ }
- /* TODO: transform that into some macros */
- snprintf(local_ip, IP_STRING_SIZE, "%i.%i.%i.%i",(ip_config->ip)[0],(ip_config->ip)[1],
- (ip_config->ip)[2],(ip_config->ip)[3]);
+ rc = ipc_gen_phone_res_check(phone_res);
+ if(rc < 0) {
+ LOGE("There was an error, aborting PDP context complete");
- snprintf(gateway, IP_STRING_SIZE, "%i.%i.%i.%i",(ip_config->ip)[0],(ip_config->ip)[1],
- (ip_config->ip)[2],(ip_config->ip)[3]);
+ // RILJ is not going to ask for fail reason
+ ril_gprs_connection_del(gprs_connection);
- snprintf(subnet_mask, IP_STRING_SIZE, "255.255.255.255");
+ RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
- snprintf(dns1, IP_STRING_SIZE, "%i.%i.%i.%i",(ip_config->dns1)[0],(ip_config->dns1)[1],
- (ip_config->dns1)[2],(ip_config->dns1)[3]);
+ LOGD("Waiting for GPRS call status");
+}
- snprintf(dns2, IP_STRING_SIZE , "%i.%i.%i.%i",(ip_config->dns2)[0],(ip_config->dns2)[1],
- (ip_config->dns2)[2],(ip_config->dns2)[3]);
+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;
- LOGD("GPRS configuration: ip:%s, gateway:%s, subnet_mask:%s, dns1:%s, dns2:%s",
- local_ip, gateway, subnet_mask ,dns1, dns2);
+ 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));
+}
+
+ // DONE: clean token after returning so we don't return twice on call_status (call_status has to check there is a valid token);
+ // TODO: trigger unsol everytime?
+ // DONE override token by the one we get here! (should be cleaned after confirming enable anyways)
+ // DONE: wait for gen_phone res at very least -> check it everytime and return if failed, or confirm disabled by call_status and then unregister
+ /*
+ * Set as enabled when:
+ * - it is disabled and status says it's now enabled -> activate iface and set config
+ * Set as disabled when:
+ * - it is enabled and status says it's now disabled -> disable iface
+ * If there is a fail reason, whatever status is, report failure to the token we haven't cleared yet!
+ * If there is no fail and we have a token, report to it, and if we go to enabled, then report ip and stuff
+ */
+
+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;
+ 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;
+
+ rc = ipc_client_gprs_get_iface(ipc_client, &interface);
+ 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);
+ }
+
+ LOGD("Using net interface: %s\n", interface);
+
+ 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);
@@ -233,56 +477,58 @@ void ipc_gprs_ip_configuration(struct ipc_message_info *info)
}
}
- rc = ipc_client_gprs_get_iface(ipc_client, &interface);
- if(rc < 0) {
- // This is not a critical issue, fallback to rmnet0
- LOGE("Failed to get interface name!");
- asprintf(&interface, "rmnet0");
- }
-
- LOGD("Iface name is %s\n", interface);
+ LOGD("GPRS configuration: ip:%s, gateway:%s, subnet_mask:%s, dns1:%s, dns2:%s",
+ ip, gateway, subnet_mask, dns1, dns2);
- rc = ifc_configure(interface,
- inet_addr(local_ip),
- inet_addr(subnet_mask),
- inet_addr(gateway),
- inet_addr(dns1),
- inet_addr(dns2));
- LOGD("ifc_configure: %d",rc);
+ rc = ifc_configure(interface, inet_addr(ip),
+ inet_addr(subnet_mask), inet_addr(gateway),
+ inet_addr(dns1), inet_addr(dns2));
- snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", interface);
- property_set(dns_prop_name, dns1);
- snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", interface);
- property_set(dns_prop_name, dns2);
- snprintf(gw_prop_name, sizeof(gw_prop_name), "net.%s.gw", interface);
- property_set(dns_prop_name, gateway);
+ if(rc < 0) {
+ LOGE("ifc_configure failed");
- response[0] = "0"; //FIXME: connection id
- response[1] = interface;
- response[2] = local_ip;
+ free(interface);
+ return -1;
+ }
- RIL_onRequestComplete(ril_state.tokens.gprs_context, RIL_E_SUCCESS, response, sizeof(response));
+ 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);
- ril_state.tokens.gprs_context = (RIL_Token) 0x00;
+ asprintf(&(setup_data_call_response[0]), "%d", gprs_connection->cid);
+ setup_data_call_response[1] = interface;
+ setup_data_call_response[2] = ip;
- // FIXME: is it wise to free returned data?
- free(interface);
+ return 0;
}
-void ril_request_deactivate_data_call(RIL_Token t, void *data, int length)
+int ipc_gprs_connection_disable(struct ril_gprs_connection *gprs_connection)
{
- struct ipc_gprs_pdp_context deactivate_message;
struct ipc_client *ipc_client;
+
+ char *interface;
int rc;
ipc_client = ((struct ipc_client_object *) ipc_fmt_client->object)->ipc_client;
- memset(&deactivate_message, 0, sizeof(deactivate_message));
- deactivate_message.unk0[1]=1;
+ rc = ipc_client_gprs_get_iface(ipc_client, &interface);
+ 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);
+ }
- /* send the struct to the modem */
- ipc_fmt_send(IPC_GPRS_PDP_CONTEXT, IPC_TYPE_SET,
- (void *) &deactivate_message, sizeof(struct ipc_gprs_pdp_context), reqGetId(t));
+ LOGD("Using net interface: %s\n", interface);
+
+ rc = ifc_down(interface);
+ free(interface);
+
+ if(rc < 0) {
+ LOGE("ifc_down failed");
+ }
if(ipc_client_gprs_handlers_available(ipc_client)) {
rc = ipc_client_gprs_deactivate(ipc_client);
@@ -292,8 +538,253 @@ void ril_request_deactivate_data_call(RIL_Token t, void *data, int length)
}
}
- // Clean the token
- ril_state.tokens.gprs_context = (RIL_Token) 0x00;
+ 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];
+ 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) {
+ LOGE("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 {
+ LOGE("GPRS interface enabled");
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ 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) {
+ LOGE("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 {
+ LOGE("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));
}
diff --git a/samsung-ril.c b/samsung-ril.c
index 7f669b5..cfd7f20 100644
--- a/samsung-ril.c
+++ b/samsung-ril.c
@@ -268,6 +268,12 @@ void ipc_fmt_dispatch(struct ipc_message_info *info)
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:
LOGD("Unhandled command: %s (%04x)", ipc_command_to_str(IPC_COMMAND(info)), IPC_COMMAND(info));
break;
@@ -462,6 +468,12 @@ void onRequest(int request, void *data, size_t datalen, RIL_Token t)
case RIL_REQUEST_DEACTIVATE_DATA_CALL:
ril_request_deactivate_data_call(t, data, datalen);
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, datalen);
@@ -516,6 +528,7 @@ void ril_globals_init(void)
ril_requests_tokens_init();
ipc_gen_phone_res_expects_init();
+ ril_gprs_connections_init();
ril_request_sms_init();
ipc_sms_tpid_queue_init();
}
@@ -542,9 +555,6 @@ const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **a
ril_env = env;
- ril_globals_init();
- ril_state_lpm();
-
ipc_fmt:
LOGD("Creating IPC FMT client");
@@ -606,6 +616,9 @@ srs:
LOGD("SRS client ready");
end:
+ ril_globals_init();
+ ril_state_lpm();
+
return &ril_ops;
}
diff --git a/samsung-ril.h b/samsung-ril.h
index a5b7cfa..5811b29 100644
--- a/samsung-ril.h
+++ b/samsung-ril.h
@@ -134,7 +134,6 @@ struct ril_tokens {
RIL_Token get_imei;
RIL_Token get_imeisv;
RIL_Token baseband_version;
- RIL_Token gprs_context;
RIL_Token registration_state;
RIL_Token gprs_registration_state;
@@ -183,8 +182,7 @@ struct ril_state {
struct ipc_call_status call_status;
- struct ipc_gprs_pdp_context gprs_context;
- struct ipc_gprs_define_pdp_context gprs_define_context;
+ int gprs_last_failed_cid;
unsigned char dtmf_tone;
@@ -349,9 +347,29 @@ void srs_snd_set_call_audio_path(struct srs_message *message);
/* GPRS */
+struct ril_gprs_connection {
+ int cid;
+ int enabled;
+ RIL_LastDataCallActivateFailCause fail_cause;
+
+ 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;
+};
+
+void ril_gprs_connections_init(void);
+int ril_gprs_connection_reg_id(void);
+struct ril_gprs_connection *ril_gprs_connection_add(void);
+void ril_gprs_connection_del(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 */