---
drivers/rilmodem/gprs-context.c | 251 +++++++++++++++++++++++++++++++++++-----
1 file changed, 225 insertions(+), 26 deletions(-)
diff --git a/drivers/rilmodem/gprs-context.c b/drivers/rilmodem/gprs-context.c
index 1e5f6ed..558231e 100644
--- a/drivers/rilmodem/gprs-context.c
+++ b/drivers/rilmodem/gprs-context.c
@@ -142,6 +142,217 @@ static void ril_gprs_context_call_list_changed(struct ril_msg
*message,
}
}
+static int gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
+ enum ofono_gprs_proto protocol,
+ char **dns_addrs)
+{
+ char **dns_ipv4_addrs, **dns_ipv6_addrs;
+ int proto;
+ int ipv4_idx, ipv6_idx;
+ int dns_strv_len;
+ int i;
+
+ if (protocol == OFONO_GPRS_PROTO_IP) {
+ ofono_gprs_context_set_ipv4_dns_servers(gc,
+ (const char **) dns_addrs);
+ return 0;
+ }
+
+ if (protocol == OFONO_GPRS_PROTO_IPV6) {
+ ofono_gprs_context_set_ipv6_dns_servers(gc,
+ (const char **) dns_addrs);
+ return 0;
+ }
+
+ dns_strv_len = g_strv_length(dns_addrs);
+
+ dns_ipv4_addrs = g_new0(char *, dns_strv_len + 1);
+ dns_ipv6_addrs = g_new0(char *, dns_strv_len + 1);
+
+ for (i = 0, ipv4_idx = 0, ipv6_idx = 0; dns_addrs[i]; i++) {
+ proto = ril_util_address_to_gprs_proto(dns_addrs[i]);
+
+ if (proto == OFONO_GPRS_PROTO_IP)
+ dns_ipv4_addrs[ipv4_idx++] = dns_addrs[i];
+
+ else if (proto == OFONO_GPRS_PROTO_IPV6)
+ dns_ipv6_addrs[ipv6_idx++] = dns_addrs[i];
+ }
+
+ if (ipv4_idx)
+ ofono_gprs_context_set_ipv4_dns_servers(gc,
+ (const char **) dns_ipv4_addrs);
+
+ if (ipv6_idx)
+ ofono_gprs_context_set_ipv6_dns_servers(gc,
+ (const char **) dns_ipv6_addrs);
+
+ g_free(dns_ipv4_addrs);
+ g_free(dns_ipv6_addrs);
+
+ return 0;
+}
+
+static int gprs_context_set_gateway(struct ofono_gprs_context *gc,
+ enum ofono_gprs_proto protocol,
+ char **gateways)
+{
+ int proto;
+ gboolean ipv4_flag, ipv6_flag;
+ int i;
+
+ if (protocol == OFONO_GPRS_PROTO_IP) {
+ ofono_gprs_context_set_ipv4_gateway(gc, gateways[0]);
+
+ return 0;
+ }
+
+ if (protocol == OFONO_GPRS_PROTO_IPV6) {
+ ofono_gprs_context_set_ipv6_gateway(gc, gateways[0]);
+
+ return 0;
+ }
+
+ ipv4_flag = FALSE;
+ ipv6_flag = FALSE;
+
+ for (i = 0; gateways[i]; i++) {
+ proto = ril_util_address_to_gprs_proto(gateways[i]);
+
+ if (!ipv4_flag && proto == OFONO_GPRS_PROTO_IP) {
+ ofono_gprs_context_set_ipv4_gateway(gc, gateways[i]);
+
+ ipv4_flag = TRUE;
+
+ } else if (!ipv6_flag && proto == OFONO_GPRS_PROTO_IPV6) {
+ ofono_gprs_context_set_ipv6_gateway(gc, gateways[i]);
+
+ ipv6_flag = TRUE;
+ }
+
+ /*
+ * both IPv4 and IPv6 gateways
+ * have been set, job done
+ */
+ if (ipv4_flag && ipv6_flag)
+ break;
+ }
+
+ return 0;
+}
+
+static int gprs_context_set_ipv4_address(struct ofono_gprs_context *gc,
+ const char *addrs)
+{
+ char **split_addrs = g_strsplit(addrs, "/", 2);
+ char *netmask;
+
+ /*
+ * Note - the address may optionally include a prefix size
+ * ( Eg. "/30" ). As this confuses NetworkManager, we
+ * explicitly strip any prefix after calculating the netmask
+ */
+ if (split_addrs == NULL || g_strv_length(split_addrs) == 0) {
+ g_strfreev(split_addrs);
+ return -1;
+ }
+
+ netmask = ril_util_get_netmask(addrs);
+
+ if (netmask)
+ ofono_gprs_context_set_ipv4_netmask(gc, netmask);
+
+ ofono_gprs_context_set_ipv4_address(gc, split_addrs[0], TRUE);
+
+ g_strfreev(split_addrs);
+
+ return 0;
+}
+
+static int gprs_context_set_ipv6_address(struct ofono_gprs_context *gc,
+ const char *addrs)
+{
+ char **split_addrs = g_strsplit(addrs, "/", 2);
+ guint64 prefix_ull;
+ char *endptr;
+ unsigned char prefix;
+
+ if (split_addrs == NULL || g_strv_length(split_addrs) == 0) {
+ g_strfreev(split_addrs);
+ return -1;
+ }
+
+ ofono_gprs_context_set_ipv6_address(gc, split_addrs[0]);
+
+ /*
+ * We will set ipv6 prefix length if present
+ * otherwise let connection manager decide
+ */
+ if (!split_addrs[1]) {
+ g_strfreev(split_addrs);
+ return 0;
+ }
+
+ prefix_ull = g_ascii_strtoull(split_addrs[1], &endptr, 10);
+
+ /* Discard in case of conversion failure or invalid prefix length */
+ if (split_addrs[1] == endptr || *endptr != '\0' || prefix_ull > 128) {
+ g_strfreev(split_addrs);
+ return -1;
+ }
+
+ prefix = prefix_ull;
+
+ ofono_gprs_context_set_ipv6_prefix_length(gc, prefix);
+
+ g_strfreev(split_addrs);
+
+ return 0;
+}
+
+static int gprs_context_set_address(struct ofono_gprs_context *gc,
+ enum ofono_gprs_proto protocol,
+ char **ip_addrs)
+{
+ int proto;
+ gboolean ipv4_flag, ipv6_flag;
+ int i;
+
+ if (protocol == OFONO_GPRS_PROTO_IP)
+ return gprs_context_set_ipv4_address(gc, ip_addrs[0]);
+
+ if (protocol == OFONO_GPRS_PROTO_IPV6)
+ return gprs_context_set_ipv6_address(gc, ip_addrs[0]);
+
+ ipv4_flag = FALSE;
+ ipv6_flag = FALSE;
+
+ for (i = 0; ip_addrs[i]; i++) {
+ proto = ril_util_address_to_gprs_proto(ip_addrs[i]);
+
+ if (!ipv4_flag && proto == OFONO_GPRS_PROTO_IP) {
+ if (gprs_context_set_ipv4_address(gc,
+ ip_addrs[i]) != 0)
+ return -1;
+
+ ipv4_flag = TRUE;
+
+ } else if (!ipv6_flag &&
+ proto == OFONO_GPRS_PROTO_IPV6) {
+ if (gprs_context_set_ipv6_address(gc,
+ ip_addrs[i]) != 0)
+ return -1;
+
+ ipv6_flag = TRUE;
+ }
+
+ if (ipv4_flag && ipv6_flag)
+ break;
+ }
+
+ return 0;
+}
+
static void ril_setup_data_call_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -238,8 +449,12 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer
user_data)
goto error_free;
}
- ofono_gprs_context_set_ipv4_dns_servers(gc,
- (const char **) dns_addrs);
+ if (gprs_context_set_dns_servers(gc,
+ protocol, dns_addrs) != 0) {
+ g_strfreev(dns_addrs);
+ goto error_free;
+ }
+
g_strfreev(dns_addrs);
}
@@ -256,7 +471,11 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer
user_data)
goto error_free;
}
- ofono_gprs_context_set_ipv4_gateway(gc, gateways[0]);
+ if (gprs_context_set_gateway(gc, protocol, gateways) != 0) {
+ g_strfreev(gateways);
+ goto error_free;
+ }
+
g_strfreev(gateways);
} else
goto error_free;
@@ -274,8 +493,6 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer
user_data)
*/
if (raw_addrs) {
char **ip_addrs = g_strsplit(raw_addrs, " ", 3);
- char **split_ip_addr;
- char *netmask;
if (ip_addrs == NULL || g_strv_length(ip_addrs) == 0) {
g_strfreev(ip_addrs);
@@ -284,30 +501,12 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer
user_data)
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);
-
- netmask = ril_util_get_netmask(ip_addrs[0]);
-
- g_strfreev(ip_addrs);
-
- if (split_ip_addr == NULL ||
- g_strv_length(split_ip_addr) == 0) {
- g_strfreev(split_ip_addr);
+ if (gprs_context_set_address(gc, protocol, ip_addrs) != 0) {
+ g_strfreev(ip_addrs);
goto error_free;
}
- if (netmask)
- ofono_gprs_context_set_ipv4_netmask(gc, netmask);
-
- ofono_gprs_context_set_ipv4_address(gc, split_ip_addr[0], TRUE);
+ g_strfreev(ip_addrs);
}
g_free(type);
--
1.9.1