summaryrefslogtreecommitdiff
path: root/src/modem-manager/nm-modem-gsm-hso.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modem-manager/nm-modem-gsm-hso.c')
-rw-r--r--src/modem-manager/nm-modem-gsm-hso.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/src/modem-manager/nm-modem-gsm-hso.c b/src/modem-manager/nm-modem-gsm-hso.c
new file mode 100644
index 0000000000..343bfa3f24
--- /dev/null
+++ b/src/modem-manager/nm-modem-gsm-hso.c
@@ -0,0 +1,348 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include "nm-modem-gsm-hso.h"
+#include "nm-device-private.h"
+#include "nm-device-interface.h"
+#include "NetworkManagerSystem.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-gsm.h"
+#include "nm-modem-types.h"
+#include "nm-utils.h"
+
+G_DEFINE_TYPE (NMModemGsmHso, nm_modem_gsm_hso, NM_TYPE_MODEM_GSM)
+
+#define NM_MODEM_GSM_HSO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM_GSM_HSO, NMModemGsmHsoPrivate))
+
+typedef struct {
+ char *netdev_iface;
+ NMIP4Config *pending_ip4_config;
+} NMModemGsmHsoPrivate;
+
+#define HSO_SECRETS_TRIES "gsm-secrets-tries"
+
+static char *
+get_network_device (NMDevice *device)
+{
+ char *result = NULL;
+ GError *error = NULL;
+ GValue value = { 0, };
+
+ if (!dbus_g_proxy_call (nm_modem_get_proxy (NM_MODEM (device), "org.freedesktop.DBus.Properties"),
+ "Get", &error,
+ G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM_GSM_HSO,
+ G_TYPE_STRING, "NetworkDevice",
+ G_TYPE_INVALID,
+ G_TYPE_VALUE, &value,
+ G_TYPE_INVALID)) {
+ nm_warning ("Could not get HSO device's network interface: %s", error->message);
+ g_error_free (error);
+ } else {
+ if (G_VALUE_HOLDS_STRING (&value))
+ result = g_value_dup_string (&value);
+ else
+ nm_warning ("Could not get HSO device's network interface: wrong type '%s'",
+ G_VALUE_TYPE_NAME (&value));
+
+ g_value_unset (&value);
+ }
+
+ return result;
+}
+
+NMDevice *
+nm_modem_gsm_hso_new (const char *path,
+ const char *data_device,
+ const char *driver)
+{
+ NMDevice *device;
+
+ g_return_val_if_fail (path != NULL, NULL);
+ g_return_val_if_fail (data_device != NULL, NULL);
+ g_return_val_if_fail (driver != NULL, NULL);
+
+ device = (NMDevice *) g_object_new (NM_TYPE_MODEM_GSM_HSO,
+ NM_DEVICE_INTERFACE_UDI, path,
+ NM_DEVICE_INTERFACE_IFACE, data_device,
+ NM_DEVICE_INTERFACE_DRIVER, driver,
+ NM_DEVICE_INTERFACE_MANAGED, TRUE,
+ NM_MODEM_PATH, path,
+ NULL);
+
+ if (device) {
+ NMModemGsmHsoPrivate *priv;
+
+ priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
+ priv->netdev_iface = get_network_device (device);
+ if (!priv->netdev_iface) {
+ g_object_unref (device);
+ device = NULL;
+ }
+ }
+
+ return device;
+}
+
+/*****************************************************************************/
+
+static NMSetting *
+get_setting (NMModemGsmHso *modem, GType setting_type)
+{
+ NMActRequest *req;
+ NMSetting *setting = NULL;
+
+ req = nm_device_get_act_request (NM_DEVICE (modem));
+ if (req) {
+ NMConnection *connection;
+
+ connection = nm_act_request_get_connection (req);
+ if (connection)
+ setting = nm_connection_get_setting (connection, setting_type);
+ }
+
+ return setting;
+}
+
+static void
+hso_auth_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+ NMDevice *device = NM_DEVICE (user_data);
+ GError *error = NULL;
+
+ if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID))
+ nm_device_activate_schedule_stage3_ip_config_start (device);
+ else {
+ nm_warning ("Authentication failed: %s", error->message);
+ g_error_free (error);
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED);
+ }
+}
+
+static void
+do_hso_auth (NMModemGsmHso *device)
+{
+ NMSettingGsm *s_gsm;
+ const char *username;
+ const char *password;
+
+ s_gsm = NM_SETTING_GSM (get_setting (device, NM_TYPE_SETTING_GSM));
+ username = nm_setting_gsm_get_username (s_gsm);
+ password = nm_setting_gsm_get_password (s_gsm);
+
+ dbus_g_proxy_begin_call (nm_modem_get_proxy (NM_MODEM (device), MM_DBUS_INTERFACE_MODEM_GSM_HSO),
+ "Authenticate", hso_auth_done,
+ device, NULL,
+ G_TYPE_STRING, username ? username : "",
+ G_TYPE_STRING, password ? password : "",
+ G_TYPE_INVALID);
+}
+
+static NMActStageReturn
+real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
+{
+ NMActRequest *req;
+ NMConnection *connection;
+ const char *setting_name;
+ GPtrArray *hints = NULL;
+ const char *hint1 = NULL, *hint2 = NULL;
+ guint32 tries;
+
+ req = nm_device_get_act_request (device);
+ g_assert (req);
+ connection = nm_act_request_get_connection (req);
+ g_assert (connection);
+
+ setting_name = nm_connection_need_secrets (connection, &hints);
+ if (!setting_name) {
+ do_hso_auth (NM_MODEM_GSM_HSO (device));
+ return NM_ACT_STAGE_RETURN_POSTPONE;
+ }
+
+ if (hints) {
+ if (hints->len > 0)
+ hint1 = g_ptr_array_index (hints, 0);
+ if (hints->len > 1)
+ hint2 = g_ptr_array_index (hints, 1);
+ }
+
+ nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE);
+
+ tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), HSO_SECRETS_TRIES));
+ nm_act_request_request_connection_secrets (req,
+ setting_name,
+ tries ? TRUE : FALSE,
+ SECRETS_CALLER_HSO_GSM,
+ hint1,
+ hint2);
+ g_object_set_data (G_OBJECT (connection), HSO_SECRETS_TRIES, GUINT_TO_POINTER (++tries));
+
+ if (hints)
+ g_ptr_array_free (hints, TRUE);
+
+ return NM_ACT_STAGE_RETURN_POSTPONE;
+}
+
+static void
+get_ip4_config_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+ NMDevice *device = NM_DEVICE (user_data);
+ guint32 ip4_address;
+ GArray *dns_array;
+ GError *error = NULL;
+
+ if (dbus_g_proxy_end_call (proxy, call_id, &error,
+ G_TYPE_UINT, &ip4_address,
+ DBUS_TYPE_G_UINT_ARRAY, &dns_array,
+ G_TYPE_INVALID)) {
+
+ NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
+ NMIP4Address *addr;
+ int i;
+
+ addr = nm_ip4_address_new ();
+ nm_ip4_address_set_address (addr, ip4_address);
+ nm_ip4_address_set_prefix (addr, 32);
+
+ priv->pending_ip4_config = nm_ip4_config_new ();
+ nm_ip4_config_take_address (priv->pending_ip4_config, addr);
+
+ for (i = 0; i < dns_array->len; i++)
+ nm_ip4_config_add_nameserver (priv->pending_ip4_config,
+ g_array_index (dns_array, guint32, i));
+
+ nm_device_activate_schedule_stage4_ip_config_get (device);
+ } else {
+ nm_warning ("Retrieving IP4 configuration failed: %s", error->message);
+ g_error_free (error);
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+ }
+}
+
+static NMActStageReturn
+real_act_stage3_ip_config_start (NMDevice *device, NMDeviceStateReason *reason)
+{
+ dbus_g_proxy_begin_call (nm_modem_get_proxy (NM_MODEM (device), MM_DBUS_INTERFACE_MODEM_GSM_HSO),
+ "GetIP4Config", get_ip4_config_done,
+ device, NULL,
+ G_TYPE_INVALID);
+
+ return NM_ACT_STAGE_RETURN_POSTPONE;
+}
+
+static NMActStageReturn
+real_act_stage4_get_ip4_config (NMDevice *device,
+ NMIP4Config **config,
+ NMDeviceStateReason *reason)
+{
+ NMModemGsmHso *self = NM_MODEM_GSM_HSO (device);
+ NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (self);
+ gboolean no_firmware = FALSE;
+
+ nm_device_set_ip_iface (device, priv->netdev_iface);
+ if (!nm_device_hw_bring_up (device, TRUE, &no_firmware)) {
+ if (no_firmware)
+ *reason = NM_DEVICE_STATE_REASON_FIRMWARE_MISSING;
+ else
+ *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
+ return NM_ACT_STAGE_RETURN_FAILURE;
+ }
+
+ *config = priv->pending_ip4_config;
+ priv->pending_ip4_config = NULL;
+
+ return NM_ACT_STAGE_RETURN_SUCCESS;
+}
+
+static void
+real_deactivate (NMDevice *device)
+{
+ NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
+
+ if (priv->pending_ip4_config) {
+ g_object_unref (priv->pending_ip4_config);
+ priv->pending_ip4_config = NULL;
+ }
+
+ if (priv->netdev_iface) {
+ nm_system_device_flush_ip4_routes_with_iface (priv->netdev_iface);
+ nm_system_device_flush_ip4_addresses_with_iface (priv->netdev_iface);
+ nm_system_device_set_up_down_with_iface (priv->netdev_iface, FALSE, NULL);
+ }
+ nm_device_set_ip_iface (device, NULL);
+
+ if (NM_DEVICE_CLASS (nm_modem_gsm_hso_parent_class)->deactivate)
+ NM_DEVICE_CLASS (nm_modem_gsm_hso_parent_class)->deactivate (device);
+}
+
+static gboolean
+real_hw_is_up (NMDevice *device)
+{
+ NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
+ NMDeviceState state;
+
+ state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
+ if (priv->pending_ip4_config || state == NM_DEVICE_STATE_IP_CONFIG || state == NM_DEVICE_STATE_ACTIVATED)
+ return nm_system_device_is_up_with_iface (priv->netdev_iface);
+
+ return TRUE;
+}
+
+static gboolean
+real_hw_bring_up (NMDevice *device, gboolean *no_firmware)
+{
+ NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (device);
+ NMDeviceState state;
+
+ state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
+ if (priv->pending_ip4_config || state == NM_DEVICE_STATE_IP_CONFIG || state == NM_DEVICE_STATE_ACTIVATED)
+ return nm_system_device_set_up_down_with_iface (priv->netdev_iface, TRUE, no_firmware);
+
+ return TRUE;
+}
+
+static void
+real_connect (NMModem *modem, const char *number)
+{
+ nm_device_activate_schedule_stage2_device_config (NM_DEVICE (modem));
+}
+
+/*****************************************************************************/
+
+static void
+nm_modem_gsm_hso_init (NMModemGsmHso *self)
+{
+}
+
+static void
+finalize (GObject *object)
+{
+ NMModemGsmHsoPrivate *priv = NM_MODEM_GSM_HSO_GET_PRIVATE (object);
+
+ g_free (priv->netdev_iface);
+
+ G_OBJECT_CLASS (nm_modem_gsm_hso_parent_class)->finalize (object);
+}
+
+static void
+nm_modem_gsm_hso_class_init (NMModemGsmHsoClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
+ NMModemClass *modem_class = NM_MODEM_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (NMModemGsmHsoPrivate));
+
+ object_class->finalize = finalize;
+
+ device_class->act_stage2_config = real_act_stage2_config;
+ device_class->act_stage3_ip_config_start = real_act_stage3_ip_config_start;
+ device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
+ device_class->deactivate = real_deactivate;
+ device_class->hw_is_up = real_hw_is_up;
+ device_class->hw_bring_up = real_hw_bring_up;
+
+ modem_class->connect = real_connect;
+}