summaryrefslogtreecommitdiffstats
path: root/drivers/rilmodem/gprs-context.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rilmodem/gprs-context.c')
-rw-r--r--drivers/rilmodem/gprs-context.c246
1 files changed, 177 insertions, 69 deletions
diff --git a/drivers/rilmodem/gprs-context.c b/drivers/rilmodem/gprs-context.c
index 56757b93..286c48e4 100644
--- a/drivers/rilmodem/gprs-context.c
+++ b/drivers/rilmodem/gprs-context.c
@@ -98,46 +98,50 @@ static void ril_gprs_context_call_list_changed(struct ril_msg *message,
{
struct ofono_gprs_context *gc = user_data;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
- struct ril_data_call *call = NULL;
- struct ril_data_call_list *call_list;
- gboolean active_cid_found = FALSE;
- gboolean disconnect = FALSE;
- GSList *iterator = NULL;
-
- call_list = g_ril_unsol_parse_data_call_list(gcd->ril, message);
- if (call_list == NULL)
- return;
-
- DBG("*gc: %p num calls: %d", gc, g_slist_length(call_list->calls));
+ struct parcel rilp;
+ int num_calls;
+ int cid;
+ int active;
+ int i;
- for (iterator = call_list->calls; iterator; iterator = iterator->next) {
- call = (struct ril_data_call *) iterator->data;
+ if (gcd->state == STATE_IDLE)
+ return;
- if (call->cid == gcd->active_rild_cid) {
- active_cid_found = TRUE;
- DBG("found call - cid: %d", call->cid);
+ g_ril_init_parcel(message, &rilp);
+
+ /* Version */
+ parcel_r_int32(&rilp);
+ num_calls = parcel_r_int32(&rilp);
+
+ for (i = 0; i < num_calls; i++) {
+ parcel_r_int32(&rilp); /* status */
+ parcel_r_int32(&rilp); /* ignore */
+ cid = parcel_r_int32(&rilp);
+ active = parcel_r_int32(&rilp);
+ parcel_skip_string(&rilp); /* type */
+ parcel_skip_string(&rilp); /* ifname */
+ parcel_skip_string(&rilp); /* addresses */
+ parcel_skip_string(&rilp); /* dns */
+ parcel_skip_string(&rilp); /* gateways */
+
+ /* malformed check */
+ if (rilp.malformed) {
+ ofono_error("%s: malformed parcel received", __func__);
+ return;
+ }
- if (call->active == 0) {
- DBG("call !active; notify disconnect: %d",
- call->cid);
- disconnect = TRUE;
- }
+ if (cid != gcd->active_rild_cid)
+ continue;
- break;
- }
- }
+ if (active != 0)
+ return;
- if ((disconnect == TRUE || active_cid_found == FALSE)
- && gcd->state != STATE_IDLE) {
- ofono_info("Clearing active context; disconnect: %d"
- " active_cid_found: %d active_ctx_cid: %d",
- disconnect, active_cid_found, gcd->active_ctx_cid);
+ DBG("call !active; notify disconnect: %d", cid);
ofono_gprs_context_deactivated(gc, gcd->active_ctx_cid);
set_context_disconnected(gcd);
+ return;
}
-
- g_ril_unsol_free_data_call_list(call_list);
}
static void ril_setup_data_call_cb(struct ril_msg *message, gpointer user_data)
@@ -146,8 +150,11 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer user_data)
ofono_gprs_context_cb_t cb = cbd->cb;
struct ofono_gprs_context *gc = cbd->user;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
- struct ril_data_call *call = NULL;
- struct ril_data_call_list *call_list = NULL;
+ struct parcel rilp;
+ unsigned int active, cid, num_calls, retry, status;
+ char *type = NULL, *ifname = NULL, *raw_addrs = NULL;
+ char *raw_dns = NULL, *raw_gws = NULL;
+ int protocol;
DBG("*gc: %p", gc);
@@ -155,63 +162,158 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer user_data)
ofono_error("%s: setup data call failed for apn: %s - %s",
__func__, gcd->apn,
ril_error_to_string(message->error));
-
set_context_disconnected(gcd);
goto error;
}
- call_list = g_ril_unsol_parse_data_call_list(gcd->ril, message);
- if (call_list == NULL) {
- /* parsing failed, need to actually disconnect */
+ g_ril_init_parcel(message, &rilp);
+
+ parcel_r_int32(&rilp); /* Version */
+ num_calls = parcel_r_int32(&rilp);
+
+ if (num_calls != 1) {
+ ofono_error("%s: setup_data_call reply for apn: %s,"
+ " includes %d calls",
+ __func__, gcd->apn, num_calls);
disconnect_context(gc);
goto error;
}
- if (g_slist_length(call_list->calls) != 1) {
- ofono_error("%s: setup_data_call reply for apn: %s,"
- " includes %d calls",
+ status = parcel_r_int32(&rilp);
+
+ if (status != PDP_FAIL_NONE) {
+ ofono_error("%s: status for apn: %s, is non-zero: %s",
__func__, gcd->apn,
- g_slist_length(call_list->calls));
+ ril_pdp_fail_to_string(status));
- disconnect_context(gc);
+ set_context_disconnected(gcd);
goto error;
}
- call = (struct ril_data_call *) call_list->calls->data;
+ retry = parcel_r_int32(&rilp); /* ignore */
+ cid = parcel_r_int32(&rilp);
+ active = parcel_r_int32(&rilp);
+ type = parcel_r_string(&rilp);
+ ifname = parcel_r_string(&rilp);
+ raw_addrs = parcel_r_string(&rilp);
+ raw_dns = parcel_r_string(&rilp);
+ raw_gws = parcel_r_string(&rilp);
+
+ /* malformed check */
+ if (rilp.malformed) {
+ ofono_error("%s: malformed parcel received", __func__);
+ goto error_free;
+ }
- /* Check for valid DNS settings, except for MMS contexts */
- if (gcd->type != OFONO_GPRS_CONTEXT_TYPE_MMS
- && (call->dns_addrs == NULL
- || g_strv_length(call->dns_addrs) == 0)) {
- ofono_error("%s: no DNS in context of type %d",
- __func__, gcd->type);
- disconnect_context(gc);
- goto error;
+ DBG("[status=%d,retry=%d,cid=%d,active=%d,type=%s,ifname=%s,"
+ "address=%s,dns=%s,gateways=%s]",
+ status, retry, cid, active, type,
+ ifname, raw_addrs, raw_dns, raw_gws);
+
+ protocol = ril_protocol_string_to_ofono_protocol(type);
+ if (protocol < 0) {
+ ofono_error("%s: invalid type(protocol) specified: %s",
+ __func__, type);
+ goto error_free;
}
- if (call->status != PDP_FAIL_NONE) {
- ofono_error("%s: reply->status for apn: %s, is non-zero: %s",
- __func__, gcd->apn,
- ril_pdp_fail_to_string(call->status));
+ if (ifname == NULL || strlen(ifname) == 0) {
+ ofono_error("%s: no interface specified: %s",
+ __func__, ifname);
+ goto error_free;
+ }
- set_context_disconnected(gcd);
- goto error;
+ ofono_gprs_context_set_interface(gc, ifname);
+
+ /* Split DNS addresses */
+ if (raw_dns) {
+ char **dns_addrs = g_strsplit(raw_dns, " ", 3);
+
+ /* Check for valid DNS settings, except for MMS contexts */
+ if (gcd->type != OFONO_GPRS_CONTEXT_TYPE_MMS &&
+ (dns_addrs == NULL ||
+ g_strv_length(dns_addrs) == 0)) {
+ g_strfreev(dns_addrs);
+ ofono_error("%s: no DNS: %s", __func__, raw_dns);
+ goto error_free;
+ }
+
+ ofono_gprs_context_set_ipv4_dns_servers(gc,
+ (const char **) dns_addrs);
+ g_strfreev(dns_addrs);
}
- gcd->active_rild_cid = call->cid;
- gcd->state = STATE_ACTIVE;
+ /*
+ * RILD can return multiple addresses; oFono only supports
+ * setting a single IPv4 gateway.
+ */
+ if (raw_gws) {
+ char **gateways = g_strsplit(raw_gws, " ", 3);
- ofono_gprs_context_set_interface(gc, call->ifname);
- ofono_gprs_context_set_ipv4_netmask(gc,
- ril_util_get_netmask(call->ip_addr));
+ if (gateways == NULL || g_strv_length(gateways) == 0) {
+ g_strfreev(gateways);
+ ofono_error("%s: no gateways: %s", __func__, raw_gws);
+ goto error_free;
+ }
- ofono_gprs_context_set_ipv4_address(gc, call->ip_addr, TRUE);
- ofono_gprs_context_set_ipv4_gateway(gc, call->gateways[0]);
+ ofono_gprs_context_set_ipv4_gateway(gc, gateways[0]);
+ g_strfreev(gateways);
+ } else
+ goto error_free;
+
+ /* TODO:
+ * RILD can return multiple addresses; oFono only supports
+ * setting a single IPv4 address. At this time, we only
+ * use the first address. It's possible that a RIL may
+ * just specify the end-points of the point-to-point
+ * connection, in which case this code will need to
+ * changed to handle such a device.
+ *
+ * For now split into a maximum of three, and only use
+ * the first address for the remaining operations.
+ */
+ if (raw_addrs) {
+ char **ip_addrs = g_strsplit(raw_addrs, " ", 3);
+ char **split_ip_addr;
+
+ if (ip_addrs == NULL || g_strv_length(ip_addrs) == 0) {
+ g_strfreev(ip_addrs);
+ ofono_error("%s: no ip addrs: %s",
+ __func__, raw_addrs);
+ goto error_free;
+ }
+
+ if (g_strv_length(ip_addrs) > 1)
+ ofono_warn("%s: more than one IP addr returned: %s",
+ __func__, raw_addrs);
+ /*
+ * Note - the address may optionally include a prefix size
+ * ( Eg. "/30" ). As this confuses NetworkManager, we
+ * explicitly strip any prefix after calculating the netmask
+ */
+ split_ip_addr = g_strsplit(ip_addrs[0], "/", 2);
+ g_strfreev(ip_addrs);
+
+ if (split_ip_addr == NULL ||
+ g_strv_length(split_ip_addr) == 0) {
+ g_strfreev(split_ip_addr);
+ goto error_free;
+ }
- ofono_gprs_context_set_ipv4_dns_servers(gc,
- (const char **) call->dns_addrs);
+ ofono_gprs_context_set_ipv4_netmask(gc,
+ ril_util_get_netmask(split_ip_addr[0]));
- g_ril_unsol_free_data_call_list(call_list);
+ ofono_gprs_context_set_ipv4_address(gc, split_ip_addr[0], TRUE);
+ }
+
+ g_free(type);
+ g_free(ifname);
+ g_free(raw_addrs);
+ g_free(raw_dns);
+ g_free(raw_gws);
+
+ gcd->active_rild_cid = cid;
+ gcd->state = STATE_ACTIVE;
/* activate listener for data call changed events.... */
gcd->call_list_id =
@@ -222,9 +324,15 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer user_data)
CALLBACK_WITH_SUCCESS(cb, cbd->data);
return;
-error:
- g_ril_unsol_free_data_call_list(call_list);
+error_free:
+ g_free(type);
+ g_free(ifname);
+ g_free(raw_addrs);
+ g_free(raw_dns);
+ g_free(raw_gws);
+ disconnect_context(gc);
+error:
CALLBACK_WITH_FAILURE(cb, cbd->data);
}