diff options
-rw-r--r-- | call.c | 39 | ||||
-rw-r--r-- | gprs.c | 745 | ||||
-rw-r--r-- | samsung-ril.c | 22 | ||||
-rw-r--r-- | samsung-ril.h | 28 |
4 files changed, 703 insertions, 131 deletions
@@ -49,6 +49,18 @@ unsigned char ipc2ril_call_list_entry_state(unsigned char call_state) } } +RIL_LastCallFailCause ipc2ril_call_fail_cause(unsigned char end_cause) +{ + switch(end_cause) { + case IPC_CALL_END_CAUSE_NORMAL: + case IPC_CALL_END_CAUSE_REJECTED: + return CALL_FAIL_NORMAL; + case IPC_CALL_END_CAUSE_UNSPECIFIED: + default: + return CALL_FAIL_ERROR_UNSPECIFIED; + } +} + /** * In: RIL_UNSOL_CALL_RING * Ring indication for an incoming call (eg, RING or CRING event). @@ -70,6 +82,13 @@ void ipc_call_incoming(struct ipc_message_info *info) */ void ipc_call_status(struct ipc_message_info *info) { + struct ipc_call_status *call_status = + (struct ipc_call_status *) info->data; + + memcpy(&(ril_state.call_status), call_status, sizeof(struct ipc_call_status)); + + LOGD("Updating Call Status data"); + RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); } @@ -226,9 +245,27 @@ void ril_request_answer(RIL_Token t) } /** + * In: RIL_REQUEST_LAST_CALL_FAIL_CAUSE + * Reason why last call was terminated + */ +void ril_request_last_call_fail_cause(RIL_Token t) +{ + RIL_LastCallFailCause fail_cause; + struct ipc_call_status *call_status = + &(ril_state.call_status); + + fail_cause = ipc2ril_call_fail_cause(call_status->end_cause); + + // Empty global call_status + memset(call_status, 0, sizeof(struct ipc_call_status)); + + RIL_onRequestComplete(t, RIL_E_SUCCESS, &fail_cause, sizeof(RIL_LastCallFailCause)); +} + +/** * In: IPC_CALL_BURST_DTMF * Send DTMF burst. RILJ only sends 1 DTMF tone to send at a time. - * + * * Out: IPC_CALL_BURST_DTMF * It should be possible to send multiple DTMF tones at once in this message. * First byte should be DTMF tones count. @@ -1,8 +1,8 @@ /** * 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> - * Copyright (C) 2011 Paul Kocialkowski <contact@oaulk.fr> * * samsung-ril is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,88 +25,271 @@ #define LOG_TAG "RIL-GPRS" #include <utils/Log.h> #include <cutils/properties.h> -#include <netutils/ifc.h> #include "samsung-ril.h" #include "util.h" -/* FIXME: we don't want these hardcoded */ -#define IP_STRING_SIZE 15 + 1 +struct ril_gprs_connection **ril_gprs_connections; +int ril_gprs_connections_count; -void ipc_gprs_pdp_context_complete(struct ipc_message_info *info) +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"); - // 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; @@ -117,107 +300,156 @@ 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); + + if(!gprs_connection) { + LOGE("Unable to find GPRS connection, aborting"); + + RIL_onRequestComplete(reqGetToken(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return; + } - 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]; + LOGD("Obtained IP Configuration"); - char dns_prop_name[PROPERTY_KEY_MAX]; - char gw_prop_name[PROPERTY_KEY_MAX]; + // Copy the obtained IP configuration to the GPRS connection structure + memcpy(&(gprs_connection->ip_configuration), ip_configuration, sizeof(struct ipc_gprs_ip_configuration)); - char *interface; + LOGD("Waiting for GPRS call status"); +} - RIL_Data_Call_Response_v6 data_call_response; - char *response[3]; +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; + } + + 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; - /* 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]); + char *interface = NULL; + char *ip; + char *gateway; + char *subnet_mask; + char *dns1; + char *dns2; - 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]); + char prop_name[PROPERTY_KEY_MAX]; - snprintf(subnet_mask, IP_STRING_SIZE, "255.255.255.255"); + int rc; - 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]); + ipc_client = ((struct ipc_client_object *) ipc_fmt_client->object)->ipc_client; - 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]); + ip_configuration = &(gprs_connection->ip_configuration); - LOGD("GPRS configuration: ip:%s, gateway:%s, subnet_mask:%s, dns1:%s, dns2:%s", - local_ip, gateway, subnet_mask ,dns1, dns2); + 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); @@ -227,62 +459,82 @@ void ipc_gprs_ip_configuration(struct ipc_message_info *info) } } - rc = ipc_client_gprs_get_iface(ipc_client, &interface); + rc = ipc_client_gprs_get_iface(ipc_client, &interface, gprs_connection->cid); if(rc < 0) { - // This is not a critical issue, fallback to rmnet0 + // This is not a critical issue, fallback to rmnet LOGE("Failed to get interface name!"); - asprintf(&interface, "rmnet0"); + asprintf(&interface, "rmnet%d", gprs_connection->cid - 1); } - LOGD("Iface name is %s\n", interface); + if(gprs_connection->interface == NULL && interface != NULL) { + gprs_connection->interface = strdup(interface); + } - rc = ifc_configure(interface, - inet_addr(local_ip), - ipv4NetmaskToPrefixLength(inet_addr(subnet_mask)), - inet_addr(gateway), - inet_addr(dns1), - inet_addr(dns2)); - LOGD("ifc_configure: %d",rc); -/* - 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); -*/ - - data_call_response.status = 0; - data_call_response.cid = 0; - data_call_response.active = 1; - data_call_response.type = "IP"; - data_call_response.ifname = interface; - data_call_response.addresses = local_ip; - data_call_response.dnses = dns1; - data_call_response.gateways = gateway; - - RIL_onRequestComplete(ril_state.tokens.gprs_context, RIL_E_SUCCESS, &data_call_response, sizeof(data_call_response)); - - ril_state.tokens.gprs_context = (RIL_Token) 0x00; - - // FIXME: is it wise to free returned data? - free(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; } -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; + 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; + } - /* 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); + + 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); @@ -292,8 +544,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] = { 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; + } - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); + 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)); } diff --git a/samsung-ril.c b/samsung-ril.c index 8f15810..daa756a 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; @@ -443,6 +449,9 @@ void onRequest(int request, void *data, size_t datalen, RIL_Token t) 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, datalen); break; @@ -459,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); @@ -513,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(); } @@ -539,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"); @@ -603,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 b0e46e4..493fb43 100644 --- a/samsung-ril.h +++ b/samsung-ril.h @@ -135,7 +135,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; @@ -182,8 +181,9 @@ struct ril_state { struct ipc_net_regist gprs_netinfo; struct ipc_net_current_plmn plmndata; - struct ipc_gprs_pdp_context gprs_context; - struct ipc_gprs_define_pdp_context gprs_define_context; + struct ipc_call_status call_status; + + int gprs_last_failed_cid; unsigned char dtmf_tone; @@ -334,6 +334,7 @@ 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); @@ -348,9 +349,30 @@ void srs_snd_set_call_audio_path(struct srs_message *message); /* GPRS */ +struct ril_gprs_connection { + int cid; + int enabled; + RIL_LastDataCallActivateFailCause fail_cause; + char *interface; + + 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 */ |