bearer-qmi: refactor connection context setup logic

Place all the logic in a separate load_settings_from_bearer() method
that takes care of propagating all bearer settings to the connect
context.
This commit is contained in:
Aleksander Morgado
2021-04-08 11:28:02 +02:00
parent fffe49d03e
commit ce383abfe1

View File

@@ -28,6 +28,7 @@
#include <libmm-glib.h> #include <libmm-glib.h>
#include "mm-iface-modem.h" #include "mm-iface-modem.h"
#include "mm-iface-modem-3gpp-profile-manager.h"
#include "mm-bearer-qmi.h" #include "mm-bearer-qmi.h"
#include "mm-modem-helpers-qmi.h" #include "mm-modem-helpers-qmi.h"
#include "mm-port-enums-types.h" #include "mm-port-enums-types.h"
@@ -438,43 +439,44 @@ typedef enum {
typedef struct { typedef struct {
MMBearerQmi *self; MMBearerQmi *self;
ConnectStep step; MMBaseModem *modem;
MMPort *data; ConnectStep step;
MMPortQmi *qmi; MMPort *data;
QmiSioPort sio_port; MMPortQmi *qmi;
MMBearerMultiplexSupport multiplex; QmiSioPort sio_port;
gboolean explicit_qmi_open;
gchar *user;
gchar *password;
gchar *apn;
QmiWdsAuthentication auth;
gboolean no_ip_family_preference;
MMBearerIpMethod ip_method;
gboolean explicit_qmi_open;
gchar *user;
gchar *password;
gchar *apn;
QmiWdsAuthentication auth;
gboolean no_ip_family_preference;
MMBearerMultiplexSupport multiplex;
QmiWdaDataAggregationProtocol dap; QmiWdaDataAggregationProtocol dap;
guint mux_id; guint mux_id;
gchar *link_prefix_hint; gchar *link_prefix_hint;
gchar *link_name; gchar *link_name;
MMPort *link; MMPort *link;
MMBearerIpMethod ip_method; gboolean ipv4;
gboolean running_ipv4;
gboolean ipv4; QmiClientWds *client_ipv4;
gboolean running_ipv4; guint packet_service_status_ipv4_indication_id;
QmiClientWds *client_ipv4; guint event_report_ipv4_indication_id;
guint packet_service_status_ipv4_indication_id; guint32 packet_data_handle_ipv4;
guint event_report_ipv4_indication_id;
guint32 packet_data_handle_ipv4;
MMBearerIpConfig *ipv4_config; MMBearerIpConfig *ipv4_config;
GError *error_ipv4; GError *error_ipv4;
gboolean ipv6; gboolean ipv6;
gboolean running_ipv6; gboolean running_ipv6;
QmiClientWds *client_ipv6; QmiClientWds *client_ipv6;
guint packet_service_status_ipv6_indication_id; guint packet_service_status_ipv6_indication_id;
guint event_report_ipv6_indication_id; guint event_report_ipv6_indication_id;
guint32 packet_data_handle_ipv6; guint32 packet_data_handle_ipv6;
MMBearerIpConfig *ipv6_config; MMBearerIpConfig *ipv6_config;
GError *error_ipv6; GError *error_ipv6;
} ConnectContext; } ConnectContext;
static void static void
@@ -544,8 +546,9 @@ connect_context_free (ConnectContext *ctx)
g_clear_object (&ctx->ipv6_config); g_clear_object (&ctx->ipv6_config);
g_clear_object (&ctx->data); g_clear_object (&ctx->data);
g_object_unref (ctx->qmi); g_clear_object (&ctx->qmi);
g_object_unref (ctx->self); g_clear_object (&ctx->modem);
g_clear_object (&ctx->self);
g_slice_free (ConnectContext, ctx); g_slice_free (ConnectContext, ctx);
} }
@@ -1958,167 +1961,138 @@ cancel_operation_cancellable (GCancellable *cancellable,
g_cancellable_cancel (operation_cancellable); g_cancellable_cancel (operation_cancellable);
} }
static void static gboolean
_connect (MMBaseBearer *_self, load_settings_from_bearer (MMBearerQmi *self,
GCancellable *cancellable, MMBaseModem *modem,
GAsyncReadyCallback callback, ConnectContext *ctx,
gpointer user_data) MMBearerProperties *properties,
GError **error)
{ {
MMBearerQmi *self = MM_BEARER_QMI (_self); MMBearerAllowedAuth bearer_auth;
MMBearerProperties *properties = NULL; MMBearerIpFamily ip_family;
ConnectContext *ctx; GError *inner_error = NULL;
MMBaseModem *modem = NULL;
MMPort *data = NULL;
MMPortQmi *qmi = NULL;
QmiSioPort sio_port = QMI_SIO_PORT_NONE;
GError *error = NULL;
const gchar *apn;
GTask *task;
GCancellable *operation_cancellable = NULL;
g_object_get (self,
MM_BASE_BEARER_MODEM, &modem,
NULL);
g_assert (modem);
/* Grab a data port */
data = mm_base_modem_get_best_data_port (modem, MM_PORT_TYPE_NET);
if (!data) {
g_task_report_new_error (
self,
callback,
user_data,
_connect,
MM_CORE_ERROR,
MM_CORE_ERROR_NOT_FOUND,
"No valid data port found to launch connection");
goto out;
}
/* Each data port has a single QMI port associated */
qmi = mm_broadband_modem_qmi_get_port_qmi_for_data (MM_BROADBAND_MODEM_QMI (modem), data, &sio_port, &error);
if (!qmi) {
g_task_report_error (
self,
callback,
user_data,
_connect,
error);
goto out;
}
/* Check whether we have an APN */
apn = mm_bearer_properties_get_apn (mm_base_bearer_peek_config (_self));
/* Is this a 3GPP only modem and no APN was given? If so, error */
if (mm_iface_modem_is_3gpp_only (MM_IFACE_MODEM (modem)) && !apn) {
g_task_report_new_error (
self,
callback,
user_data,
_connect,
MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"3GPP connection logic requires APN setting");
goto out;
}
/* Is this a 3GPP2 only modem and APN was given? If so, error */
if (mm_iface_modem_is_cdma_only (MM_IFACE_MODEM (modem)) && apn) {
g_task_report_new_error (
self,
callback,
user_data,
_connect,
MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"3GPP2 doesn't support APN setting");
goto out;
}
ctx = g_slice_new0 (ConnectContext);
ctx->self = g_object_ref (self);
ctx->qmi = g_object_ref (qmi);
ctx->sio_port = sio_port;
ctx->dap = mm_port_qmi_get_data_aggregation_protocol (ctx->qmi);
ctx->mux_id = QMI_DEVICE_MUX_ID_UNBOUND;
ctx->data = g_object_ref (data);
ctx->step = CONNECT_STEP_FIRST;
ctx->ip_method = MM_BEARER_IP_METHOD_UNKNOWN;
/* If no multiplex setting given by the user, assume requested */ /* If no multiplex setting given by the user, assume requested */
ctx->multiplex = MM_BEARER_MULTIPLEX_SUPPORT_REQUESTED; ctx->multiplex = mm_bearer_properties_get_multiplex (properties);
if (ctx->multiplex == MM_BEARER_MULTIPLEX_SUPPORT_UNKNOWN)
ctx->multiplex = MM_BEARER_MULTIPLEX_SUPPORT_REQUESTED;
g_object_get (self, /* The link prefix hint given must be modem-specific */
MM_BASE_BEARER_CONFIG, &properties, if (ctx->multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUESTED ||
NULL); ctx->multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUIRED) {
ctx->link_prefix_hint = g_strdup_printf ("qmapmux%u.", mm_base_modem_get_dbus_id (MM_BASE_MODEM (modem)));
}
/* APN settings */
ctx->apn = g_strdup (mm_bearer_properties_get_apn (properties));
/* Is this a 3GPP only modem and no APN was given? If so, error */
if (mm_iface_modem_is_3gpp_only (MM_IFACE_MODEM (modem)) && !ctx->apn) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"3GPP connection logic requires APN setting");
return FALSE;
}
/* Is this a 3GPP2 only modem and APN was given? If so, error */
if (mm_iface_modem_is_cdma_only (MM_IFACE_MODEM (modem)) && ctx->apn) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"3GPP2 doesn't support APN setting");
return FALSE;
}
/* IP type settings */
ip_family = mm_bearer_properties_get_ip_type (properties);
if (mm_3gpp_normalize_ip_family (&ip_family))
ctx->no_ip_family_preference = TRUE;
if (ip_family & MM_BEARER_IP_FAMILY_IPV4)
ctx->ipv4 = TRUE;
if (ip_family & MM_BEARER_IP_FAMILY_IPV6)
ctx->ipv6 = TRUE;
if (ip_family & MM_BEARER_IP_FAMILY_IPV4V6) {
ctx->ipv4 = TRUE;
ctx->ipv6 = TRUE;
}
if (!ctx->ipv4 && !ctx->ipv6) {
g_autofree gchar *str = NULL;
str = mm_bearer_ip_family_build_string_from_mask (ip_family);
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Unsupported IP type requested: '%s'", str);
return FALSE;
}
/* Auth settings */
ctx->user = g_strdup (mm_bearer_properties_get_user (properties));
ctx->password = g_strdup (mm_bearer_properties_get_password (properties));
if (!ctx->user && !ctx->password)
ctx->auth = QMI_WDS_AUTHENTICATION_NONE;
else {
bearer_auth = mm_bearer_properties_get_allowed_auth (properties);
ctx->auth = mm_bearer_allowed_auth_to_qmi_authentication (bearer_auth, self, &inner_error);
if (inner_error) {
g_propagate_error (error, inner_error);
return FALSE;
}
}
return TRUE;
}
static void
_connect (MMBaseBearer *_self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBearerQmi *self = MM_BEARER_QMI (_self);
ConnectContext *ctx;
GError *error = NULL;
GTask *task;
g_autoptr(GCancellable) operation_cancellable = NULL;
g_autoptr(MMBaseModem) modem = NULL;
g_autoptr(MMBearerProperties) properties = NULL;
operation_cancellable = g_cancellable_new (); operation_cancellable = g_cancellable_new ();
task = g_task_new (self, operation_cancellable, callback, user_data); task = g_task_new (self, operation_cancellable, callback, user_data);
g_task_set_check_cancellable (task, FALSE); g_task_set_check_cancellable (task, FALSE);
g_object_get (self,
MM_BASE_BEARER_MODEM, &modem,
MM_BASE_BEARER_CONFIG, &properties,
NULL);
g_assert (modem);
ctx = g_slice_new0 (ConnectContext);
ctx->self = g_object_ref (self);
ctx->modem = g_object_ref (modem);
ctx->mux_id = QMI_DEVICE_MUX_ID_UNBOUND;
ctx->sio_port = QMI_SIO_PORT_NONE;
ctx->step = CONNECT_STEP_FIRST;
ctx->ip_method = MM_BEARER_IP_METHOD_UNKNOWN;
g_task_set_task_data (task, ctx, (GDestroyNotify)connect_context_free); g_task_set_task_data (task, ctx, (GDestroyNotify)connect_context_free);
if (properties) { /* Grab a data port */
MMBearerAllowedAuth auth; ctx->data = mm_base_modem_get_best_data_port (modem, MM_PORT_TYPE_NET);
MMBearerIpFamily ip_family; if (!ctx->data) {
MMBearerMultiplexSupport multiplex; g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
"No valid data port found to launch connection");
ctx->apn = g_strdup (mm_bearer_properties_get_apn (properties)); g_object_unref (task);
ctx->user = g_strdup (mm_bearer_properties_get_user (properties)); return;
ctx->password = g_strdup (mm_bearer_properties_get_password (properties));
ip_family = mm_bearer_properties_get_ip_type (properties);
if (mm_3gpp_normalize_ip_family (&ip_family))
ctx->no_ip_family_preference = TRUE;
if (ip_family & MM_BEARER_IP_FAMILY_IPV4)
ctx->ipv4 = TRUE;
if (ip_family & MM_BEARER_IP_FAMILY_IPV6)
ctx->ipv6 = TRUE;
if (ip_family & MM_BEARER_IP_FAMILY_IPV4V6) {
ctx->ipv4 = TRUE;
ctx->ipv6 = TRUE;
}
if (!ctx->ipv4 && !ctx->ipv6) {
gchar *str;
str = mm_bearer_ip_family_build_string_from_mask (ip_family);
g_task_return_new_error (
task,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED,
"Unsupported IP type requested: '%s'",
str);
g_object_unref (task);
g_free (str);
goto out;
}
auth = mm_bearer_properties_get_allowed_auth (properties);
g_object_unref (properties);
if (!ctx->user && !ctx->password)
ctx->auth = QMI_WDS_AUTHENTICATION_NONE;
else {
auth = mm_bearer_properties_get_allowed_auth (properties);
ctx->auth = mm_bearer_allowed_auth_to_qmi_authentication (auth, self, &error);
if (error) {
g_task_return_error (task, error);
g_object_unref (task);
goto out;
}
}
multiplex = mm_bearer_properties_get_multiplex (properties);
if (multiplex != MM_BEARER_MULTIPLEX_SUPPORT_UNKNOWN)
ctx->multiplex = multiplex;
} }
if (ctx->multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUESTED || /* Each data port has a single QMI port associated */
ctx->multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUIRED) { ctx->qmi = mm_broadband_modem_qmi_get_port_qmi_for_data (MM_BROADBAND_MODEM_QMI (modem), ctx->data, &ctx->sio_port, &error);
/* the link prefix hint given must be modem-specific */ if (!ctx->qmi) {
ctx->link_prefix_hint = g_strdup_printf ("qmapmux%u.", mm_base_modem_get_dbus_id (MM_BASE_MODEM (modem))); g_task_return_error (task, error);
g_object_unref (task);
return;
}
ctx->dap = mm_port_qmi_get_data_aggregation_protocol (ctx->qmi);
/* load all settings from bearer */
if (!load_settings_from_bearer (self, modem, ctx, properties, &error)) {
g_prefix_error (&error, "Invalid bearer properties: ");
g_task_return_error (task, error);
g_object_unref (task);
return;
} }
/* setup network cancellable */ /* setup network cancellable */
@@ -2139,16 +2113,10 @@ _connect (MMBaseBearer *_self,
/* Run! */ /* Run! */
mm_obj_dbg (self, "launching connection with QMI port (%s) and data port (%s) (multiplex %s)", mm_obj_dbg (self, "launching connection with QMI port (%s) and data port (%s) (multiplex %s)",
mm_port_get_device (MM_PORT (qmi)), mm_port_get_device (MM_PORT (ctx->qmi)),
mm_port_get_device (data), mm_port_get_device (ctx->data),
mm_bearer_multiplex_support_get_string (ctx->multiplex)); mm_bearer_multiplex_support_get_string (ctx->multiplex));
connect_context_step (task); connect_context_step (task);
out:
g_clear_object (&operation_cancellable);
g_clear_object (&qmi);
g_clear_object (&data);
g_clear_object (&modem);
} }
/*****************************************************************************/ /*****************************************************************************/