diff options
author | Dan Williams <dcbw@redhat.com> | 2014-04-15 15:22:11 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2014-06-13 11:30:49 -0500 |
commit | ca0a567f74f30a719f11b749165731630528834a (patch) | |
tree | ff89ba16cddff33a7a9ba80f9eb49f3bb86d057a /src | |
parent | 801762835309bdaeb6c6a9758b41c58e03cbdf38 (diff) |
broadband-bearer-qmi: support IPv6 configuration and use static for IPv4
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-bearer-qmi.c | 306 |
1 files changed, 195 insertions, 111 deletions
diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c index 4c693d24..41fdc6eb 100644 --- a/src/mm-bearer-qmi.c +++ b/src/mm-bearer-qmi.c @@ -31,6 +31,7 @@ #include "mm-modem-helpers-qmi.h" #include "mm-port-enums-types.h" #include "mm-log.h" +#include "mm-modem-helpers.h" G_DEFINE_TYPE (MMBearerQmi, mm_bearer_qmi, MM_TYPE_BEARER); @@ -82,12 +83,14 @@ typedef struct { gboolean running_ipv4; QmiClientWds *client_ipv4; guint32 packet_data_handle_ipv4; + MMBearerIpConfig *ipv4_config; GError *error_ipv4; gboolean ipv6; gboolean running_ipv6; QmiClientWds *client_ipv6; guint32 packet_data_handle_ipv6; + MMBearerIpConfig *ipv6_config; GError *error_ipv6; } ConnectContext; @@ -99,14 +102,12 @@ connect_context_complete_and_free (ConnectContext *ctx) g_free (ctx->apn); g_free (ctx->user); g_free (ctx->password); - if (ctx->error_ipv4) - g_error_free (ctx->error_ipv4); - if (ctx->error_ipv6) - g_error_free (ctx->error_ipv6); - if (ctx->client_ipv4) - g_object_unref (ctx->client_ipv4); - if (ctx->client_ipv6) - g_object_unref (ctx->client_ipv6); + g_clear_error (&ctx->error_ipv4); + g_clear_error (&ctx->error_ipv6); + g_clear_object (&ctx->client_ipv4); + g_clear_object (&ctx->client_ipv6); + g_clear_object (&ctx->ipv4_config); + g_clear_object (&ctx->ipv6_config); g_object_unref (ctx->data); g_object_unref (ctx->qmi); g_object_unref (ctx->cancellable); @@ -247,51 +248,191 @@ build_start_network_input (ConnectContext *ctx) } static void -print_address4 (gboolean success, const char *tag, guint32 address, GError *error) +qmi_inet4_ntop (guint32 address, char *buf, const gsize buflen) { struct in_addr a = { .s_addr = GUINT32_TO_BE (address) }; - char buf[INET_ADDRSTRLEN + 1]; - if (success) { - memset (buf, 0, sizeof (buf)); - if (inet_ntop (AF_INET, &a, buf, sizeof (buf) - 1)) - mm_dbg (" %s: %s", tag, buf); - else - mm_dbg (" %s: failed (address conversion error)", tag); - return; + g_assert (buflen >= INET_ADDRSTRLEN); + + /* We can ignore inet_ntop() return value if 'buf' is + * at least INET_ADDRSTRLEN in size. */ + memset (buf, 0, buflen); + g_assert (inet_ntop (AF_INET, &a, buf, buflen)); +} + +static MMBearerIpConfig * +get_ipv4_config (QmiMessageWdsGetCurrentSettingsOutput *output, guint32 mtu) +{ + MMBearerIpConfig *config; + char buf[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + const gchar *dns[3] = { 0 }; + guint dns_idx = 0; + guint32 addr = 0; + GError *error = NULL; + guint32 prefix = 0; + + /* IPv4 subnet mask */ + if (!qmi_message_wds_get_current_settings_output_get_ipv4_gateway_subnet_mask (output, &addr, &error)) { + mm_dbg ("Failed to read IPv4 netmask (%s)", error->message); + g_clear_error (&error); + return NULL; } - mm_dbg (" %s: failed (%s)", tag, error ? error->message : "unknown"); + qmi_inet4_ntop (addr, buf, sizeof (buf)); + prefix = mm_netmask_to_cidr (buf); + + /* IPv4 address */ + if (!qmi_message_wds_get_current_settings_output_get_ipv4_address (output, &addr, &error)) { + mm_dbg ("IPv4 family but no IPv4 address (%s)", error->message); + g_clear_error (&error); + return NULL; + } + + mm_dbg ("QMI IPv4 Settings:"); + + config = mm_bearer_ip_config_new (); + mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_STATIC); + + /* IPv4 address */ + qmi_inet4_ntop (addr, buf, sizeof (buf)); + mm_bearer_ip_config_set_address (config, buf); + mm_bearer_ip_config_set_prefix (config, prefix); + mm_dbg (" Address: %s/%d", buf, prefix); + + /* IPv4 gateway address */ + if (qmi_message_wds_get_current_settings_output_get_ipv4_gateway_address (output, &addr, &error)) { + qmi_inet4_ntop (addr, buf, sizeof (buf)); + mm_bearer_ip_config_set_gateway (config, buf); + mm_dbg (" Gateway: %s", buf); + } else { + mm_dbg (" Gateway: failed (%s)", error->message); + g_clear_error (&error); + } + + /* IPv4 DNS #1 */ + if (qmi_message_wds_get_current_settings_output_get_primary_ipv4_dns_address (output, &addr, &error)) { + qmi_inet4_ntop (addr, buf, sizeof (buf)); + dns[dns_idx++] = buf; + mm_dbg (" DNS #1: %s", buf); + } else { + mm_dbg (" DNS #1: failed (%s)", error->message); + g_clear_error (&error); + } + + /* IPv6 DNS #2 */ + if (qmi_message_wds_get_current_settings_output_get_secondary_ipv4_dns_address (output, &addr, &error)) { + qmi_inet4_ntop (addr, buf2, sizeof (buf2)); + dns[dns_idx++] = buf2; + mm_dbg (" DNS #2: %s", buf2); + } else { + mm_dbg (" DNS #2: failed (%s)", error->message); + g_clear_error (&error); + } + + if (dns_idx > 0) + mm_bearer_ip_config_set_dns (config, (const gchar **) &dns); + + if (mtu) { + mm_bearer_ip_config_set_mtu (config, mtu); + mm_dbg (" MTU: %d", mtu); + } + + return config; } static void -print_address6 (gboolean success, - const char *tag, - GArray *array, - guint32 prefix, - GError *error) +qmi_inet6_ntop (GArray *array, char *buf, const gsize buflen) { struct in6_addr a; - char buf[INET6_ADDRSTRLEN + 1]; guint32 i; - if (success) { - g_assert (array); - g_assert (array->len == 8); + g_assert (array); + g_assert (array->len == 8); + g_assert (buflen >= INET6_ADDRSTRLEN); - memset (buf, 0, sizeof (buf)); - for (i = 0; i < array->len; i++) - a.s6_addr16[i] = GUINT16_TO_BE (g_array_index (array, guint16, i)); + for (i = 0; i < array->len; i++) + a.s6_addr16[i] = GUINT16_TO_BE (g_array_index (array, guint16, i)); - if (inet_ntop (AF_INET6, &a, buf, sizeof (buf) - 1)) - mm_dbg (" %s: %s/%d", tag, buf, prefix); - else - mm_dbg (" %s: failed (address conversion error)", tag); + /* We can ignore inet_ntop() return value if 'buf' is + * at least INET6_ADDRSTRLEN in size. */ + memset (buf, 0, buflen); + g_assert (inet_ntop (AF_INET6, &a, buf, buflen)); +} - g_array_free (array, TRUE); - return; +static MMBearerIpConfig * +get_ipv6_config (QmiMessageWdsGetCurrentSettingsOutput *output, guint32 mtu) +{ + MMBearerIpConfig *config; + char buf[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; + const gchar *dns[3] = { 0 }; + guint dns_idx = 0; + GArray *array; + GError *error = NULL; + guint8 prefix = 0; + + /* If the message has an IPv6 address, create an IPv6 bearer config */ + if (!qmi_message_wds_get_current_settings_output_get_ipv6_address (output, &array, &prefix, &error)) { + mm_dbg ("IPv6 family but no IPv6 address (%s)", error->message); + g_clear_error (&error); + return NULL; } - mm_dbg (" %s: failed (%s)", tag, error ? error->message : "unknown"); + mm_dbg ("QMI IPv6 Settings:"); + + config = mm_bearer_ip_config_new (); + mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_STATIC); + + /* IPv6 address */ + qmi_inet6_ntop (array, buf, sizeof (buf)); + g_array_unref (array); + + mm_bearer_ip_config_set_address (config, buf); + mm_bearer_ip_config_set_prefix (config, prefix); + mm_dbg (" Address: %s/%d", buf, prefix); + + /* IPv6 gateway address */ + if (qmi_message_wds_get_current_settings_output_get_ipv6_gateway_address (output, &array, &prefix, &error)) { + qmi_inet6_ntop (array, buf, sizeof (buf)); + mm_bearer_ip_config_set_gateway (config, buf); + mm_dbg (" Gateway: %s", buf); + g_array_unref (array); + } else { + mm_dbg (" Gateway: failed (%s)", error->message); + g_clear_error (&error); + } + + /* IPv6 DNS #1 */ + if (qmi_message_wds_get_current_settings_output_get_ipv6_primary_dns_address (output, &array, &error)) { + qmi_inet6_ntop (array, buf, sizeof (buf)); + dns[dns_idx++] = buf; + mm_dbg (" DNS #1: %s", buf); + g_array_unref (array); + } else { + mm_dbg (" DNS #1: failed (%s)", error->message); + g_clear_error (&error); + } + + /* IPv6 DNS #2 */ + if (qmi_message_wds_get_current_settings_output_get_ipv6_secondary_dns_address (output, &array, &error)) { + qmi_inet6_ntop (array, buf2, sizeof (buf2)); + dns[dns_idx++] = buf2; + mm_dbg (" DNS #2: %s", buf2); + g_array_unref (array); + } else { + mm_dbg (" DNS #2: failed (%s)", error->message); + g_clear_error (&error); + } + + if (dns_idx > 0) + mm_bearer_ip_config_set_dns (config, (const gchar **) &dns); + + if (mtu) { + mm_bearer_ip_config_set_mtu (config, mtu); + mm_dbg (" MTU: %d", mtu); + } + + return config; } static void @@ -312,73 +453,33 @@ get_current_settings_ready (QmiClientWds *client, mm_info ("error: couldn't get current settings: %s", error->message); g_error_free (error); } else { - gboolean success; - guint32 addr, mtu, i; + QmiWdsIpFamily ip_family = QMI_WDS_IP_FAMILY_UNSPECIFIED; + guint32 mtu = 0; GArray *array; - guint8 prefix; - - /* If the message has an IPv4 address, print IPv4 settings */ - if (qmi_message_wds_get_current_settings_output_get_ipv4_address (output, &addr, &error)) { - mm_dbg ("QMI IPv4 Settings:"); - /* IPv4 address */ - print_address4 (TRUE, "Address", addr, error); - g_clear_error (&error); - - /* IPv4 gateway address */ - success = qmi_message_wds_get_current_settings_output_get_ipv4_gateway_address (output, &addr, &error); - print_address4 (success, "Gateway", addr, error); - g_clear_error (&error); - - /* IPv4 subnet mask */ - success = qmi_message_wds_get_current_settings_output_get_ipv4_gateway_subnet_mask (output, &addr, &error); - print_address4 (success, "Netmask", addr, error); - g_clear_error (&error); - - /* IPv4 DNS #1 */ - success = qmi_message_wds_get_current_settings_output_get_primary_ipv4_dns_address (output, &addr, &error); - print_address4 (success, " DNS #1", addr, error); - g_clear_error (&error); - - /* IPv4 DNS #2 */ - success = qmi_message_wds_get_current_settings_output_get_secondary_ipv4_dns_address (output, &addr, &error); - print_address4 (success, " DNS #2", addr, error); - g_clear_error (&error); - } else { - /* no IPv4 configuration */ + if (!qmi_message_wds_get_current_settings_output_get_ip_family (output, &ip_family, &error)) { + mm_dbg (" IP Family: failed (%s); assuming IPv4", error->message); g_clear_error (&error); + ip_family = QMI_WDS_IP_FAMILY_IPV4; } + mm_dbg (" IP Family: %s", + (ip_family == QMI_WDS_IP_FAMILY_IPV4) ? "IPv4" : + (ip_family == QMI_WDS_IP_FAMILY_IPV6) ? "IPv6" : "unknown"); - /* If the message has an IPv6 address, print IPv6 settings */ - if (qmi_message_wds_get_current_settings_output_get_ipv6_address (output, &array, &prefix, &error)) { - mm_dbg ("QMI IPv6 Settings:"); - - /* IPv6 address */ - print_address6 (TRUE, "Address", array, prefix, error); - g_clear_error (&error); - - /* IPv6 gateway address */ - success = qmi_message_wds_get_current_settings_output_get_ipv6_gateway_address (output, &array, &prefix, &error); - print_address6 (success, "Gateway", array, prefix, error); - g_clear_error (&error); - - /* IPv6 DNS #1 */ - success = qmi_message_wds_get_current_settings_output_get_ipv6_primary_dns_address (output, &array, &error); - print_address6 (success, " DNS #1", array, 0, error); - g_clear_error (&error); - - /* IPv6 DNS #2 */ - success = qmi_message_wds_get_current_settings_output_get_ipv6_secondary_dns_address (output, &array, &error); - print_address6 (success, " DNS #2", array, 0, error); - g_clear_error (&error); - } else { - /* no IPv6 configuration */ + if (!qmi_message_wds_get_current_settings_output_get_mtu (output, &mtu, &error)) { + mm_dbg (" MTU: failed (%s)", error->message); g_clear_error (&error); } + if (ip_family == QMI_WDS_IP_FAMILY_IPV4) + ctx->ipv4_config = get_ipv4_config (output, mtu); + else if (ip_family == QMI_WDS_IP_FAMILY_IPV6) + ctx->ipv6_config = get_ipv6_config (output, mtu); + /* Domain names */ if (qmi_message_wds_get_current_settings_output_get_domain_name_list (output, &array, &error)) { GString *s = g_string_sized_new (array ? (array->len * 20) : 1); + guint i; for (i = 0; array && (i < array->len); i++) { if (s->len) @@ -391,13 +492,6 @@ get_current_settings_ready (QmiClientWds *client, mm_dbg (" Domains: failed (%s)", error ? error->message : "unknown"); g_clear_error (&error); } - - if (qmi_message_wds_get_current_settings_output_get_mtu (output, &mtu, &error)) - mm_dbg (" MTU: %d", mtu); - else { - mm_dbg (" MTU: failed (%s)", error ? error->message : "unknown"); - g_clear_error (&error); - } } if (output) @@ -728,8 +822,6 @@ connect_context_step (ConnectContext *ctx) case CONNECT_STEP_LAST: /* If one of IPv4 or IPv6 succeeds, we're connected */ if (ctx->packet_data_handle_ipv4 || ctx->packet_data_handle_ipv6) { - MMBearerIpConfig *config; - /* Port is connected; update the state */ mm_port_set_connected (MM_PORT (ctx->data), TRUE); @@ -751,19 +843,11 @@ connect_context_step (ConnectContext *ctx) ctx->self->priv->client_ipv6 = g_object_ref (ctx->client_ipv6); } - /* Build IP config; always DHCP based */ - config = mm_bearer_ip_config_new (); - mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP); - /* Set operation result */ g_simple_async_result_set_op_res_gpointer ( ctx->result, - mm_bearer_connect_result_new ( - ctx->data, - ctx->packet_data_handle_ipv4 ? config : NULL, - ctx->packet_data_handle_ipv6 ? config : NULL), + mm_bearer_connect_result_new (ctx->data, ctx->ipv4_config, ctx->ipv6_config), (GDestroyNotify)mm_bearer_connect_result_unref); - g_object_unref (config); } else { GError *error; |