summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2013-11-20 00:02:13 +0100
committerAleksander Morgado <aleksander@aleksander.es>2014-06-23 18:12:27 +0200
commit75a5c48345351585ad176b1a56c76309720248e2 (patch)
tree3e52fbf4ae2bc9e017d0f49b8feab9ca24cc68ae /plugins
parent293b032149d387109eab2164da6a7139c068c9bb (diff)
huawei: use the cdc-wdm port dialing if available
With the new 'huawei-cdc-ncm' driver in the kernel, we now may get a /dev/cdc-wdm AT-capable port exposed by the Huawei device. If so, we must use this port for NDISDUP dialling in order to get the network interface connected.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/huawei/mm-broadband-bearer-huawei.c34
-rw-r--r--plugins/huawei/mm-broadband-modem-huawei.c167
-rw-r--r--plugins/huawei/mm-broadband-modem-huawei.h3
3 files changed, 177 insertions, 27 deletions
diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c
index adc62fc4..877916ab 100644
--- a/plugins/huawei/mm-broadband-bearer-huawei.c
+++ b/plugins/huawei/mm-broadband-bearer-huawei.c
@@ -42,6 +42,25 @@ struct _MMBroadbandBearerHuaweiPrivate {
};
/*****************************************************************************/
+
+static MMPortSerialAt *
+get_dial_port (MMBroadbandModemHuawei *modem,
+ MMPort *data,
+ MMPortSerialAt *primary)
+{
+ MMPortSerialAt *dial_port;
+
+ /* See if we have a cdc-wdm AT port for the interface */
+ dial_port = (mm_broadband_modem_huawei_peek_port_at_for_data (
+ MM_BROADBAND_MODEM_HUAWEI (modem), data));
+ if (dial_port)
+ return g_object_ref (dial_port);
+
+ /* Otherwise, fallback to using the primary port for dialing */
+ return g_object_ref (primary);
+}
+
+/*****************************************************************************/
/* Connect 3GPP */
typedef enum {
@@ -67,12 +86,15 @@ static void
connect_3gpp_context_complete_and_free (Connect3gppContext *ctx)
{
g_simple_async_result_complete_in_idle (ctx->result);
+
g_object_unref (ctx->cancellable);
g_object_unref (ctx->result);
- g_object_unref (ctx->data);
- g_object_unref (ctx->primary);
g_object_unref (ctx->modem);
g_object_unref (ctx->self);
+
+ g_clear_object (&ctx->data);
+ g_clear_object (&ctx->primary);
+
g_slice_free (Connect3gppContext, ctx);
}
@@ -410,7 +432,6 @@ connect_3gpp (MMBroadbandBearer *self,
ctx = g_slice_new0 (Connect3gppContext);
ctx->self = g_object_ref (self);
ctx->modem = g_object_ref (modem);
- ctx->primary = g_object_ref (primary);
ctx->data = g_object_ref (data);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
@@ -422,6 +443,9 @@ connect_3gpp (MMBroadbandBearer *self,
g_assert (ctx->self->priv->connect_pending == NULL);
g_assert (ctx->self->priv->disconnect_pending == NULL);
+ /* Get correct dial port to use */
+ ctx->primary = get_dial_port (MM_BROADBAND_MODEM_HUAWEI (ctx->modem), ctx->data, primary);
+
/* Run! */
connect_3gpp_context_step (ctx);
}
@@ -654,7 +678,6 @@ disconnect_3gpp (MMBroadbandBearer *self,
ctx = g_slice_new0 (Disconnect3gppContext);
ctx->self = g_object_ref (self);
ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
- ctx->primary = g_object_ref (primary);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
@@ -664,6 +687,9 @@ disconnect_3gpp (MMBroadbandBearer *self,
g_assert (ctx->self->priv->connect_pending == NULL);
g_assert (ctx->self->priv->disconnect_pending == NULL);
+ /* Get correct dial port to use */
+ ctx->primary = get_dial_port (MM_BROADBAND_MODEM_HUAWEI (ctx->modem), data, primary);
+
/* Start! */
disconnect_3gpp_context_step (ctx);
}
diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c
index 1d63ca0e..3dcebe29 100644
--- a/plugins/huawei/mm-broadband-modem-huawei.c
+++ b/plugins/huawei/mm-broadband-modem-huawei.c
@@ -2098,6 +2098,149 @@ create_bearer_for_net_port (CreateBearerContext *ctx)
}
}
+static MMPortSerialAt *
+peek_port_at_for_data (MMBroadbandModemHuawei *self,
+ MMPort *port)
+{
+ GUdevClient *client;
+ GUdevDevice *data_device;
+ GUdevDevice *data_device_parent = NULL;
+ GList *cdc_wdm_at_ports = NULL;
+ GList *l;
+ MMPortSerialAt *found = NULL;
+
+ client = g_udev_client_new (NULL);
+ data_device = (g_udev_client_query_by_subsystem_and_name (
+ client,
+ "net",
+ mm_port_get_device (port)));
+
+ cdc_wdm_at_ports = mm_base_modem_find_ports (MM_BASE_MODEM (self),
+ MM_PORT_SUBSYS_USB,
+ MM_PORT_TYPE_AT,
+ NULL);
+
+ /* Get parent of the data device */
+ data_device_parent = g_udev_device_get_parent (data_device);
+ if (!data_device_parent) {
+ mm_dbg ("Cannot get parent device (%s)", mm_port_get_device (port));
+ goto out;
+ }
+
+ /* Now walk the list of cdc-wdm AT ports looking for a match */
+ for (l = cdc_wdm_at_ports; l && !found; l = g_list_next (l)) {
+ GUdevDevice *cdc_wdm_device;
+ GUdevDevice *cdc_wdm_device_parent;
+
+ g_assert (MM_IS_PORT_SERIAL_AT (l->data));
+
+ /* Get udev device for the cdc-wdm port */
+ cdc_wdm_device = (g_udev_client_query_by_subsystem_and_name (
+ client,
+ "usb",
+ mm_port_get_device (MM_PORT (l->data))));
+ if (!cdc_wdm_device) {
+ cdc_wdm_device = (g_udev_client_query_by_subsystem_and_name (
+ client,
+ "usbmisc",
+ mm_port_get_device (MM_PORT (l->data))));
+ if (!cdc_wdm_device) {
+ mm_warn ("Couldn't get udev device for cdc-wdm port '%s'",
+ mm_port_get_device (MM_PORT (l->data)));
+ continue;
+ }
+ }
+
+ /* Get parent of the cdc-wdm device */
+ cdc_wdm_device_parent = g_udev_device_get_parent (cdc_wdm_device);
+ g_object_unref (cdc_wdm_device);
+
+ if (!cdc_wdm_device_parent) {
+ mm_warn ("Couldn't get udev device parent for cdc-wdm port '%s'",
+ mm_port_get_device (MM_PORT (l->data)));
+ continue;
+ }
+
+ if (g_str_equal (g_udev_device_get_sysfs_path (data_device_parent),
+ g_udev_device_get_sysfs_path (cdc_wdm_device_parent)))
+ found = MM_PORT_SERIAL_AT (l->data);
+
+ g_object_unref (cdc_wdm_device_parent);
+ }
+
+out:
+
+ if (data_device_parent)
+ g_object_unref (data_device_parent);
+ if (data_device)
+ g_object_unref (data_device);
+ if (client)
+ g_object_unref (client);
+ if (cdc_wdm_at_ports)
+ g_list_free_full (cdc_wdm_at_ports, (GDestroyNotify)g_object_unref);
+
+ return found;
+}
+
+
+MMPortSerialAt *
+mm_broadband_modem_huawei_peek_port_at_for_data (MMBroadbandModemHuawei *self,
+ MMPort *port)
+{
+ MMPortSerialAt *found;
+
+ g_assert (self->priv->ndisdup_support == FEATURE_SUPPORTED);
+
+ found = peek_port_at_for_data (self, port);
+ if (!found)
+ mm_warn ("Couldn't find associated cdc-wdm port for 'net/%s'",
+ mm_port_get_device (port));
+ return found;
+}
+
+static void
+ensure_ndisdup_support_checked (MMBroadbandModemHuawei *self,
+ MMPort *port)
+{
+ GUdevClient *client;
+ GUdevDevice *data_device;
+
+ /* Check NDISDUP support the first time we need it */
+ if (self->priv->ndisdup_support != FEATURE_SUPPORT_UNKNOWN)
+ return;
+
+ /* First, check for devices which support NDISDUP on any AT port. These
+ * devices are tagged by udev */
+ client = g_udev_client_new (NULL);
+ data_device = (g_udev_client_query_by_subsystem_and_name (
+ client,
+ "net",
+ mm_port_get_device (port)));
+ if (data_device && g_udev_device_get_property_as_boolean (data_device, "ID_MM_HUAWEI_NDISDUP_SUPPORTED")) {
+ mm_dbg ("This device (%s) can support ndisdup feature", mm_port_get_device (port));
+ self->priv->ndisdup_support = FEATURE_SUPPORTED;
+ goto out;
+ }
+
+ /* Then, look for devices which have both a net port and a cdc-wdm
+ * AT-capable port. We assume that these devices allow NDISDUP only
+ * when issued in the cdc-wdm port. */
+ if (peek_port_at_for_data (self, port)) {
+ mm_dbg ("This device (%s) can support ndisdup feature on non-serial AT port",
+ mm_port_get_device (port));
+ self->priv->ndisdup_support = FEATURE_SUPPORTED;
+ goto out;
+ }
+
+ mm_dbg ("This device (%s) can not support ndisdup feature", mm_port_get_device (port));
+ self->priv->ndisdup_support = FEATURE_NOT_SUPPORTED;
+
+out:
+ if (data_device)
+ g_object_unref (data_device);
+ if (client)
+ g_object_unref (client);
+}
static void
huawei_modem_create_bearer (MMIfaceModem *self,
@@ -2118,28 +2261,7 @@ huawei_modem_create_bearer (MMIfaceModem *self,
port = mm_base_modem_peek_best_data_port (MM_BASE_MODEM (self), MM_PORT_TYPE_NET);
if (port) {
- /* Check NDISDUP support the first time we need it */
- if (ctx->self->priv->ndisdup_support == FEATURE_SUPPORT_UNKNOWN) {
- GUdevDevice *net_port;
- GUdevClient *client;
-
- client = g_udev_client_new (NULL);
- net_port = (g_udev_client_query_by_subsystem_and_name (
- client,
- "net",
- mm_port_get_device (port)));
- if (net_port && g_udev_device_get_property_as_boolean (net_port, "ID_MM_HUAWEI_NDISDUP_SUPPORTED")) {
- mm_dbg ("This device (%s) can support ndisdup feature", mm_port_get_device (port));
- ctx->self->priv->ndisdup_support = FEATURE_SUPPORTED;
- } else {
- mm_dbg ("This device (%s) can not support ndisdup feature", mm_port_get_device (port));
- ctx->self->priv->ndisdup_support = FEATURE_NOT_SUPPORTED;
- }
- if (net_port)
- g_object_unref (net_port);
- g_object_unref (client);
- }
-
+ ensure_ndisdup_support_checked (ctx->self, port);
create_bearer_for_net_port (ctx);
return;
}
@@ -2152,7 +2274,6 @@ huawei_modem_create_bearer (MMIfaceModem *self,
ctx);
}
-
/*****************************************************************************/
/* USSD encode/decode (3GPP-USSD interface) */
diff --git a/plugins/huawei/mm-broadband-modem-huawei.h b/plugins/huawei/mm-broadband-modem-huawei.h
index 06874bcf..85bfcdf2 100644
--- a/plugins/huawei/mm-broadband-modem-huawei.h
+++ b/plugins/huawei/mm-broadband-modem-huawei.h
@@ -48,4 +48,7 @@ MMBroadbandModemHuawei *mm_broadband_modem_huawei_new (const gchar *device,
guint16 vendor_id,
guint16 product_id);
+MMPortSerialAt *mm_broadband_modem_huawei_peek_port_at_for_data (MMBroadbandModemHuawei *self,
+ MMPort *port);
+
#endif /* MM_BROADBAND_MODEM_HUAWEI_H */