diff options
Diffstat (limited to 'src/devices/wwan')
| -rw-r--r-- | src/devices/wwan/libnm-wwan.ver | 4 | ||||
| -rw-r--r-- | src/devices/wwan/nm-device-modem.c | 50 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-broadband.c | 103 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-manager.c | 813 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-manager.h | 13 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-ofono.c | 578 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem.c | 300 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem.h | 21 | ||||
| -rw-r--r-- | src/devices/wwan/nm-wwan-factory.c | 4 |
9 files changed, 1240 insertions, 646 deletions
diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver index eb577aaf..6efcb03f 100644 --- a/src/devices/wwan/libnm-wwan.ver +++ b/src/devices/wwan/libnm-wwan.ver @@ -20,7 +20,11 @@ global: nm_modem_get_type; nm_modem_get_uid; nm_modem_ip4_pre_commit; + nm_modem_manager_get; nm_modem_manager_get_type; + nm_modem_manager_name_owner_get; + nm_modem_manager_name_owner_ref; + nm_modem_manager_name_owner_unref; nm_modem_owns_port; nm_modem_set_mm_enabled; nm_modem_stage3_ip4_config_start; diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 4a4d2f2c..22fb8c67 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -364,9 +364,8 @@ device_state_changed (NMDevice *device, { NMDeviceModem *self = NM_DEVICE_MODEM (device); NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); - NMSettingsConnection *connection = nm_device_get_settings_connection (device); - g_assert (priv->modem); + g_return_if_fail (priv->modem); if (new_state == NM_DEVICE_STATE_UNAVAILABLE && old_state < NM_DEVICE_STATE_UNAVAILABLE) { @@ -374,30 +373,7 @@ device_state_changed (NMDevice *device, _LOGI (LOGD_MB, "modem state '%s'", nm_modem_state_to_string (nm_modem_get_state (priv->modem))); } - nm_modem_device_state_changed (priv->modem, new_state, old_state); - - switch (nm_device_state_reason_check (reason)) { - case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED: - case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING: - case NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED: - case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED: - case NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED: - case NM_DEVICE_STATE_REASON_GSM_SIM_WRONG: - case NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: - case NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED: - case NM_DEVICE_STATE_REASON_GSM_APN_FAILED: - /* Block autoconnect of the just-failed connection for situations - * where a retry attempt would just fail again. - */ - if (connection) { - nm_settings_connection_set_autoconnect_blocked_reason (connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_BLOCKED); - } - break; - default: - break; - } } static NMDeviceCapabilities @@ -664,6 +640,16 @@ set_modem (NMDeviceModem *self, NMModem *modem) g_signal_connect (modem, "notify::" NM_MODEM_SIM_OPERATOR_ID, G_CALLBACK (ids_changed_cb), self); } +static guint32 +get_dhcp_timeout (NMDevice *device, int addr_family) +{ + /* DHCP is always done by the modem firmware, not by the network, and + * by the time we get around to DHCP the firmware should already know + * the IP addressing details. So the DHCP timeout can be much shorter. + */ + return 15; +} + /*****************************************************************************/ static void @@ -718,18 +704,6 @@ nm_device_modem_init (NMDeviceModem *self) { } -static void -constructed (GObject *object) -{ - G_OBJECT_CLASS (nm_device_modem_parent_class)->constructed (object); - - /* DHCP is always done by the modem firmware, not by the network, and - * by the time we get around to DHCP the firmware should already know - * the IP addressing details. So the DHCP timeout can be much shorter. - */ - nm_device_set_dhcp_timeout (NM_DEVICE (object), 15); -} - NMDevice * nm_device_modem_new (NMModem *modem) { @@ -786,7 +760,6 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; - object_class->constructed = constructed; device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_type_description = get_type_description; @@ -807,6 +780,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) device_class->is_available = is_available; device_class->get_ip_iface_identifier = get_ip_iface_identifier; device_class->get_configured_mtu = nm_modem_get_configured_mtu; + device_class->get_dhcp_timeout = get_dhcp_timeout; device_class->state_changed = device_state_changed; diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index 4b16fb14..6e5f10a0 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -90,6 +90,9 @@ typedef struct { MMBearerIpConfig *ipv4_config; MMBearerIpConfig *ipv6_config; + guint idle_id_ip4; + guint idle_id_ip6; + guint32 pin_tries; } NMModemBroadbandPrivate; @@ -860,21 +863,6 @@ set_mm_enabled (NMModem *_self, /* IPv4 method static */ static gboolean -ip4_string_to_num (const gchar *str, guint32 *out) -{ - guint32 addr = 0; - gboolean success = FALSE; - - if (!str || inet_pton (AF_INET, str, &addr) != 1) - addr = 0; - else - success = TRUE; - - *out = (guint32)addr; - return success; -} - -static gboolean static_stage3_ip4_done (NMModemBroadband *self) { GError *error = NULL; @@ -883,7 +871,7 @@ static_stage3_ip4_done (NMModemBroadband *self) const gchar *address_string; const gchar *gw_string; guint32 address_network; - guint32 gw; + guint32 gw = 0; NMPlatformIP4Address address; const gchar **dns; guint i; @@ -895,7 +883,7 @@ static_stage3_ip4_done (NMModemBroadband *self) /* Fully fail if invalid IP address retrieved */ address_string = mm_bearer_ip_config_get_address (self->_priv.ipv4_config); - if (!ip4_string_to_num (address_string, &address_network)) { + if (!nm_utils_parse_inaddr_bin (AF_INET, address_string, &address_network)) { error = g_error_new (NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "(%s) retrieving IP4 configuration failed: invalid address given '%s'", @@ -906,11 +894,20 @@ static_stage3_ip4_done (NMModemBroadband *self) /* Missing gateway not a hard failure */ gw_string = mm_bearer_ip_config_get_gateway (self->_priv.ipv4_config); - ip4_string_to_num (gw_string, &gw); + if ( !gw_string + || !nm_utils_parse_inaddr_bin (AF_INET, gw_string, &gw)) { + error = g_error_new (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IP4 configuration failed: invalid gateway address %s%s%s", + nm_modem_get_uid (NM_MODEM (self)), + NM_PRINT_FMT_QUOTE_STRING (gw_string)); + goto out; + } data_port = mm_bearer_get_interface (self->_priv.bearer); g_assert (data_port); - config = nm_ip4_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port)); + config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), + nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port)); memset (&address, 0, sizeof (address)); address.address = address_network; @@ -923,14 +920,30 @@ static_stage3_ip4_done (NMModemBroadband *self) _LOGI (" address %s/%d", address_string, address.plen); if (gw) { - nm_ip4_config_set_gateway (config, gw); - _LOGI (" gateway %s", gw_string); + guint32 ip4_route_table, ip4_route_metric; + + nm_modem_get_route_parameters (NM_MODEM (self), + &ip4_route_table, + &ip4_route_metric, + NULL, + NULL); + { + const NMPlatformIP4Route r = { + .rt_source = NM_IP_CONFIG_SOURCE_WWAN, + .gateway = gw, + .table_coerced = nm_platform_route_table_coerce (ip4_route_table), + .metric = ip4_route_metric, + }; + + _LOGI (" gateway %s", gw_string); + nm_ip4_config_add_route (config, &r, NULL); + } } /* DNS servers */ dns = mm_bearer_ip_config_get_dns (self->_priv.ipv4_config); for (i = 0; dns && dns[i]; i++) { - if ( ip4_string_to_num (dns[i], &address_network) + if ( nm_utils_parse_inaddr_bin (AF_INET, dns[i], &address_network) && address_network > 0) { nm_ip4_config_add_nameserver (config, address_network); _LOGI (" DNS %s", dns[i]); @@ -944,15 +957,17 @@ out: } static NMActStageReturn -static_stage3_ip4_config_start (NMModem *_self, +static_stage3_ip4_config_start (NMModem *modem, NMActRequest *req, NMDeviceStateReason *out_failure_reason) { - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + NMModemBroadband *self = NM_MODEM_BROADBAND (modem); + NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE (self); /* We schedule it in an idle just to follow the same logic as in the * generic modem implementation. */ - g_idle_add ((GSourceFunc) static_stage3_ip4_done, self); + nm_clear_g_source (&priv->idle_id_ip4); + priv->idle_id_ip4 = g_idle_add ((GSourceFunc) static_stage3_ip4_done, self); return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -1004,7 +1019,8 @@ stage3_ip6_done (NMModemBroadband *self) data_port = mm_bearer_get_interface (self->_priv.bearer); g_assert (data_port); - config = nm_ip6_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port)); + config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), + nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port)); address.plen = mm_bearer_ip_config_get_prefix (self->_priv.ipv6_config); if (address.plen <= 128) @@ -1014,7 +1030,9 @@ stage3_ip6_done (NMModemBroadband *self) address_string = mm_bearer_ip_config_get_gateway (self->_priv.ipv6_config); if (address_string) { - if (!inet_pton (AF_INET6, address_string, (void *) &(address.address))) { + guint32 ip6_route_table, ip6_route_metric; + + if (inet_pton (AF_INET6, address_string, &address.address) != 1) { error = g_error_new (NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", @@ -1022,8 +1040,23 @@ stage3_ip6_done (NMModemBroadband *self) address_string); goto out; } - _LOGI (" gateway %s", address_string); - nm_ip6_config_set_gateway (config, &address.address); + + nm_modem_get_route_parameters (NM_MODEM (self), + NULL, + NULL, + &ip6_route_table, + &ip6_route_metric); + { + const NMPlatformIP6Route r = { + .rt_source = NM_IP_CONFIG_SOURCE_WWAN, + .gateway = address.address, + .table_coerced = nm_platform_route_table_coerce (ip6_route_table), + .metric = ip6_route_metric, + }; + + _LOGI (" gateway %s", address_string); + nm_ip6_config_add_route (config, &r, NULL); + } } else if (ip_method == NM_MODEM_IP_METHOD_STATIC) { /* Gateway required for the 'static' method */ error = g_error_new (NM_DEVICE_ERROR, @@ -1052,13 +1085,15 @@ out: } static NMActStageReturn -stage3_ip6_config_request (NMModem *_self, NMDeviceStateReason *out_failure_reason) +stage3_ip6_config_request (NMModem *modem, NMDeviceStateReason *out_failure_reason) { - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + NMModemBroadband *self = NM_MODEM_BROADBAND (modem); + NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE (self); /* We schedule it in an idle just to follow the same logic as in the * generic modem implementation. */ - g_idle_add ((GSourceFunc) stage3_ip6_done, self); + nm_clear_g_source (&priv->idle_id_ip6); + priv->idle_id_ip6 = g_idle_add ((GSourceFunc) stage3_ip6_done, self); return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -1409,6 +1444,10 @@ static void dispose (GObject *object) { NMModemBroadband *self = NM_MODEM_BROADBAND (object); + NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE (self); + + nm_clear_g_source (&priv->idle_id_ip4); + nm_clear_g_source (&priv->idle_id_ip6); connect_context_clear (self); g_clear_object (&self->_priv.ipv4_config); diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c index b1f6d92e..59cd2bca 100644 --- a/src/devices/wwan/nm-modem-manager.c +++ b/src/devices/wwan/nm-modem-manager.c @@ -45,6 +45,10 @@ /*****************************************************************************/ +NM_GOBJECT_PROPERTIES_DEFINE (NMModemManager, + PROP_NAME_OWNER, +); + enum { MODEM_ADDED, LAST_SIGNAL, @@ -54,14 +58,38 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { GDBusConnection *dbus_connection; - MMManager *modem_manager; - guint mm_launch_id; - gulong mm_name_owner_changed_id; - gulong mm_object_added_id; - gulong mm_object_removed_id; + + /* used during g_bus_get() and later during mm_manager_new(). */ + GCancellable *main_cancellable; + + struct { + MMManager *manager; + GCancellable *poke_cancellable; + gulong handle_name_owner_changed_id; + gulong handle_object_added_id; + gulong handle_object_removed_id; + guint relaunch_id; + + /* this only has one use: that the <info> logging line about + * ModemManager available distinguishes between first-time + * and later name-owner-changed. */ + enum { + LOG_AVAILABLE_NOT_INITIALIZED = 0, + LOG_AVAILABLE_YES, + LOG_AVAILABLE_NO, + } log_available:3; + + GDBusProxy *proxy; + GCancellable *proxy_cancellable; + guint proxy_ref_count; + char *proxy_name_owner; + } modm; #if WITH_OFONO - GDBusProxy *ofono_proxy; + struct { + GDBusProxy *proxy; + GCancellable *cancellable; + } ofono; #endif GHashTable *modems; @@ -82,19 +110,35 @@ G_DEFINE_TYPE (NMModemManager, nm_modem_manager, G_TYPE_OBJECT) /*****************************************************************************/ +#define _NMLOG_DOMAIN LOGD_MB +#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "modem-manager", __VA_ARGS__) + +/*****************************************************************************/ + +NM_DEFINE_SINGLETON_GETTER (NMModemManager, nm_modem_manager_get, NM_TYPE_MODEM_MANAGER); + +/*****************************************************************************/ + +static void modm_schedule_manager_relaunch (NMModemManager *self, + guint n_seconds); +static void modm_ensure_manager (NMModemManager *self); + +/*****************************************************************************/ + static void handle_new_modem (NMModemManager *self, NMModem *modem) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); const char *path; path = nm_modem_get_path (modem); - if (g_hash_table_lookup (self->_priv.modems, path)) { + if (g_hash_table_lookup (priv->modems, path)) { g_warn_if_reached (); return; } /* Track the new modem */ - g_hash_table_insert (self->_priv.modems, g_strdup (path), modem); + g_hash_table_insert (priv->modems, g_strdup (path), modem); g_signal_emit (self, signals[MODEM_ADDED], 0, modem); } @@ -105,22 +149,27 @@ remove_one_modem (gpointer key, gpointer value, gpointer user_data) return TRUE; } +/*****************************************************************************/ + static void -clear_modem_manager (NMModemManager *self) +modm_clear_manager (NMModemManager *self) { - if (!self->_priv.modem_manager) + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + if (!priv->modm.manager) return; - nm_clear_g_signal_handler (self->_priv.modem_manager, &self->_priv.mm_name_owner_changed_id); - nm_clear_g_signal_handler (self->_priv.modem_manager, &self->_priv.mm_object_added_id); - nm_clear_g_signal_handler (self->_priv.modem_manager, &self->_priv.mm_object_removed_id); - g_clear_object (&self->_priv.modem_manager); + nm_clear_g_signal_handler (priv->modm.manager, &priv->modm.handle_name_owner_changed_id); + nm_clear_g_signal_handler (priv->modm.manager, &priv->modm.handle_object_added_id); + nm_clear_g_signal_handler (priv->modm.manager, &priv->modm.handle_object_removed_id); + g_clear_object (&priv->modm.manager); } static void -modem_object_added (MMManager *modem_manager, - MMObject *modem_object, - NMModemManager *self) +modm_handle_object_added (MMManager *modem_manager, + MMObject *modem_object, + NMModemManager *self) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); const gchar *path; MMModem *modem_iface; NMModem *modem; @@ -128,21 +177,21 @@ modem_object_added (MMManager *modem_manager, /* Ensure we don't have the same modem already */ path = mm_object_get_path (modem_object); - if (g_hash_table_lookup (self->_priv.modems, path)) { - nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path); + if (g_hash_table_lookup (priv->modems, path)) { + _LOGW ("modem with path %s already exists, ignoring", path); return; } /* Ensure we have the 'Modem' interface at least */ modem_iface = mm_object_peek_modem (modem_object); if (!modem_iface) { - nm_log_warn (LOGD_MB, "modem with path %s doesn't have the Modem interface, ignoring", path); + _LOGW ("modem with path %s doesn't have the Modem interface, ignoring", path); return; } /* Ensure we have a primary port reported */ if (!mm_modem_get_primary_port (modem_iface)) { - nm_log_warn (LOGD_MB, "modem with path %s has unknown primary port, ignoring", path); + _LOGW ("modem with path %s has unknown primary port, ignoring", path); return; } @@ -150,65 +199,68 @@ modem_object_added (MMManager *modem_manager, modem = nm_modem_broadband_new (G_OBJECT (modem_object), &error); if (modem) handle_new_modem (self, modem); - else { - nm_log_warn (LOGD_MB, "failed to create modem: %s", - error->message); - } + else + _LOGW ("failed to create modem: %s", error->message); g_clear_error (&error); } static void -modem_object_removed (MMManager *manager, - MMObject *modem_object, - NMModemManager *self) +modm_handle_object_removed (MMManager *manager, + MMObject *modem_object, + NMModemManager *self) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); NMModem *modem; const gchar *path; path = mm_object_get_path (modem_object); - modem = (NMModem *) g_hash_table_lookup (self->_priv.modems, path); + modem = (NMModem *) g_hash_table_lookup (priv->modems, path); if (!modem) return; nm_modem_emit_removed (modem); - g_hash_table_remove (self->_priv.modems, path); + g_hash_table_remove (priv->modems, path); } static void -modem_manager_available (NMModemManager *self) +modm_manager_available (NMModemManager *self) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); GList *modems, *l; - nm_log_info (LOGD_MB, "ModemManager available in the bus"); + if (priv->modm.log_available != LOG_AVAILABLE_YES) { + _LOGI ("ModemManager %savailable", priv->modm.log_available ? "now " : ""); + priv->modm.log_available = LOG_AVAILABLE_YES; + } /* Update initial modems list */ - modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->_priv.modem_manager)); + modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (priv->modm.manager)); for (l = modems; l; l = g_list_next (l)) - modem_object_added (self->_priv.modem_manager, MM_OBJECT (l->data), self); + modm_handle_object_added (priv->modm.manager, MM_OBJECT (l->data), self); g_list_free_full (modems, (GDestroyNotify) g_object_unref); } -static void schedule_modem_manager_relaunch (NMModemManager *self, - guint n_seconds); -static void ensure_modem_manager (NMModemManager *self); - static void -modem_manager_name_owner_changed (MMManager *modem_manager, - GParamSpec *pspec, - NMModemManager *self) +modm_handle_name_owner_changed (MMManager *modem_manager, + GParamSpec *pspec, + NMModemManager *self) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); gchar *name_owner; /* Quit poking, if any */ - nm_clear_g_source (&self->_priv.mm_launch_id); + nm_clear_g_source (&priv->modm.relaunch_id); name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (modem_manager)); if (!name_owner) { - nm_log_info (LOGD_MB, "ModemManager disappeared from bus"); + if (priv->modm.log_available != LOG_AVAILABLE_NO) { + _LOGI ("ModemManager %savailable", priv->modm.log_available ? "no longer " : "not "); + priv->modm.log_available = LOG_AVAILABLE_NO; + } /* If not managed by systemd, schedule relaunch */ if (!sd_booted ()) - schedule_modem_manager_relaunch (self, 0); + modm_schedule_manager_relaunch (self, 0); return; } @@ -220,18 +272,322 @@ modem_manager_name_owner_changed (MMManager *modem_manager, * nor 'object-removed' if it was created while there was no ModemManager in * the bus. This hack avoids this issue until we get a GIO with the fix * included... */ - clear_modem_manager (self); - ensure_modem_manager (self); + modm_clear_manager (self); + modm_ensure_manager (self); /* Whenever GDBusObjectManagerClient is fixed, we can just do the following: - * modem_manager_available (self); + * modm_manager_available (self); */ } +static void +modm_manager_poke_cb (GObject *connection, + GAsyncResult *res, + gpointer user_data) +{ + NMModemManager *self; + NMModemManagerPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *result = NULL; + + result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (connection), res, &error); + + if ( !result + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->modm.poke_cancellable); + + if (error) { + _LOGW ("error poking ModemManager: %s", error->message); + + /* Don't reschedule poke is MM service doesn't exist. */ + if ( !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) { + + /* Setup timeout to relaunch */ + modm_schedule_manager_relaunch (self, MODEM_POKE_INTERVAL); + } + } +} + +static void +modm_manager_poke (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + nm_clear_g_cancellable (&priv->modm.poke_cancellable); + priv->modm.poke_cancellable = g_cancellable_new (); + + /* If there is no current owner right away, ensure we poke to get one */ + g_dbus_connection_call (priv->dbus_connection, + NM_MODEM_MANAGER_MM_DBUS_SERVICE, + NM_MODEM_MANAGER_MM_DBUS_PATH, + DBUS_INTERFACE_PEER, + "Ping", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->modm.poke_cancellable, + modm_manager_poke_cb, + self); +} + +static void +modm_manager_check_name_owner (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + gs_free gchar *name_owner = NULL; + + name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (priv->modm.manager)); + if (name_owner) { + modm_manager_available (self); + return; + } + + /* If the lifecycle is not managed by systemd, poke */ + if (!sd_booted ()) + modm_manager_poke (self); +} + +static void +modm_manager_new_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + NMModemManager *self; + NMModemManagerPrivate *priv; + gs_free_error GError *error = NULL; + MMManager *modem_manager; + + modem_manager = mm_manager_new_finish (res, &error); + if ( !modem_manager + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + nm_assert (!priv->modm.manager); + + g_clear_object (&priv->main_cancellable); + + if (!modem_manager) { + /* We're not really supposed to get any error here. If we do get one, + * though, just re-schedule the MMManager creation after some time. + * During this period, name-owner changes won't be followed. */ + _LOGW ("error creating ModemManager client: %s", error->message); + /* Setup timeout to relaunch */ + modm_schedule_manager_relaunch (self, MODEM_POKE_INTERVAL); + return; + } + + priv->modm.manager = modem_manager; + + /* Setup signals in the GDBusObjectManagerClient */ + priv->modm.handle_name_owner_changed_id = + g_signal_connect (priv->modm.manager, + "notify::name-owner", + G_CALLBACK (modm_handle_name_owner_changed), + self); + priv->modm.handle_object_added_id = + g_signal_connect (priv->modm.manager, + "object-added", + G_CALLBACK (modm_handle_object_added), + self); + priv->modm.handle_object_removed_id = + g_signal_connect (priv->modm.manager, + "object-removed", + G_CALLBACK (modm_handle_object_removed), + self); + + modm_manager_check_name_owner (self); +} + +static void +modm_ensure_manager (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_assert (priv->dbus_connection); + + /* Create the GDBusObjectManagerClient. We do not request to autostart, as + * we don't really want the MMManager creation to fail. We can always poke + * later on if we want to request the autostart */ + if (!priv->modm.manager) { + if (!priv->main_cancellable) + priv->main_cancellable = g_cancellable_new (); + mm_manager_new (priv->dbus_connection, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, + priv->main_cancellable, + modm_manager_new_cb, + self); + return; + } + + /* If already available, recheck name owner! */ + modm_manager_check_name_owner (self); +} + +static gboolean +modm_schedule_manager_relaunch_cb (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + priv->modm.relaunch_id = 0; + modm_ensure_manager (self); + return G_SOURCE_REMOVE; +} + +static void +modm_schedule_manager_relaunch (NMModemManager *self, + guint n_seconds) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + /* No need to pass an extra reference to self; timeout/idle will be + * cancelled if the object gets disposed. */ + if (n_seconds) + priv->modm.relaunch_id = g_timeout_add_seconds (n_seconds, (GSourceFunc)modm_schedule_manager_relaunch_cb, self); + else + priv->modm.relaunch_id = g_idle_add ((GSourceFunc)modm_schedule_manager_relaunch_cb, self); +} + +/*****************************************************************************/ + +static void +modm_proxy_name_owner_reset (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + char *name = NULL; + + if (priv->modm.proxy) + name = g_dbus_proxy_get_name_owner (priv->modm.proxy); + + if (nm_streq0 (priv->modm.proxy_name_owner, name)) { + g_free (name); + return; + } + g_free (priv->modm.proxy_name_owner); + priv->modm.proxy_name_owner = name; + + _notify (self, PROP_NAME_OWNER); +} + +static void +modm_proxy_name_owner_changed_cb (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + modm_proxy_name_owner_reset (user_data); +} + +static void +modm_proxy_new_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + NMModemManager *self; + NMModemManagerPrivate *priv; + GDBusProxy *proxy; + gs_free_error GError *error = NULL; + + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->modm.proxy_cancellable); + + if (!proxy) { + _LOGW ("could not obtain D-Bus proxy for ModemManager: %s", error->message); + return; + } + + priv->modm.proxy = proxy; + g_signal_connect (priv->modm.proxy, "notify::g-name-owner", + G_CALLBACK (modm_proxy_name_owner_changed_cb), self); + + modm_proxy_name_owner_reset (self); +} + +void +nm_modem_manager_name_owner_ref (NMModemManager *self) +{ + NMModemManagerPrivate *priv; + + g_return_if_fail (NM_IS_MODEM_MANAGER (self)); + + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + if (priv->modm.proxy_ref_count++ > 0) { + /* only try once to create the proxy. If proxy creation + * for the first "ref" failed, it's unclear what to do. + * The proxy is hosed. */ + return; + } + + nm_assert (!priv->modm.proxy && !priv->modm.proxy_cancellable); + + priv->modm.proxy_cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + NM_MODEM_MANAGER_MM_DBUS_SERVICE, + NM_MODEM_MANAGER_MM_DBUS_PATH, + NM_MODEM_MANAGER_MM_DBUS_INTERFACE, + priv->modm.proxy_cancellable, + modm_proxy_new_cb, + self); +} + +void +nm_modem_manager_name_owner_unref (NMModemManager *self) +{ + NMModemManagerPrivate *priv; + + g_return_if_fail (NM_IS_MODEM_MANAGER (self)); + + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (priv->modm.proxy_ref_count > 0); + + if (--priv->modm.proxy_ref_count > 0) + return; + + nm_clear_g_cancellable (&priv->modm.proxy_cancellable); + g_clear_object (&priv->modm.proxy); + + modm_proxy_name_owner_reset (self); +} + +const char * +nm_modem_manager_name_owner_get (NMModemManager *self) +{ + g_return_val_if_fail (NM_IS_MODEM_MANAGER (self), NULL); + nm_assert (NM_MODEM_MANAGER_GET_PRIVATE (self)->modm.proxy_ref_count > 0); + + return NM_MODEM_MANAGER_GET_PRIVATE (self)->modm.proxy_name_owner; +} + +/*****************************************************************************/ + #if WITH_OFONO + static void ofono_create_modem (NMModemManager *self, const char *path) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); NMModem *modem = NULL; /* Ensure duplicate modems aren't created. Because we're not using the @@ -239,12 +595,12 @@ ofono_create_modem (NMModemManager *self, const char *path) * receive ModemAdded signals before GetModems() returns, so some of the * modems returned from GetModems() may already have been created. */ - if (!g_hash_table_lookup (self->_priv.modems, path)) { + if (!g_hash_table_lookup (priv->modems, path)) { modem = nm_modem_ofono_new (path); if (modem) handle_new_modem (self, modem); else - nm_log_warn (LOGD_MB, "Failed to create oFono modem for %s", path); + _LOGW ("Failed to create oFono modem for %s", path); } } @@ -256,80 +612,96 @@ ofono_signal_cb (GDBusProxy *proxy, gpointer user_data) { NMModemManager *self = NM_MODEM_MANAGER (user_data); + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); gchar *object_path; NMModem *modem; if (g_strcmp0 (signal_name, "ModemAdded") == 0) { g_variant_get (parameters, "(oa{sv})", &object_path, NULL); - nm_log_info (LOGD_MB, "oFono modem appeared: %s", object_path); + _LOGI ("oFono modem appeared: %s", object_path); ofono_create_modem (NM_MODEM_MANAGER (user_data), object_path); g_free (object_path); } else if (g_strcmp0 (signal_name, "ModemRemoved") == 0) { g_variant_get (parameters, "(o)", &object_path); - nm_log_info (LOGD_MB, "oFono modem removed: %s", object_path); + _LOGI ("oFono modem removed: %s", object_path); - modem = (NMModem *) g_hash_table_lookup (self->_priv.modems, object_path); + modem = (NMModem *) g_hash_table_lookup (priv->modems, object_path); if (modem) { nm_modem_emit_removed (modem); - g_hash_table_remove (self->_priv.modems, object_path); + g_hash_table_remove (priv->modems, object_path); } else { - nm_log_warn (LOGD_MB, "could not remove modem %s, not found in table", - object_path); + _LOGW ("could not remove modem %s, not found in table", + object_path); } g_free (object_path); } } static void -ofono_enumerate_devices_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) +ofono_enumerate_devices_done (GObject *proxy, + GAsyncResult *res, + gpointer user_data) { - NMModemManager *manager = NM_MODEM_MANAGER (user_data); + NMModemManager *self; + NMModemManagerPrivate *priv; gs_free_error GError *error = NULL; GVariant *results; GVariantIter *iter; const char *path; - results = g_dbus_proxy_call_finish (proxy, res, &error); - if (results) { - g_variant_get (results, "(a(oa{sv}))", &iter); - while (g_variant_iter_loop (iter, "(&oa{sv})", &path, NULL)) - ofono_create_modem (manager, path); - g_variant_iter_free (iter); - g_variant_unref (results); - } + results = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error); + if ( !results + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - if (error) { - nm_log_warn (LOGD_MB, "failed to enumerate oFono devices: %s", - error->message); + self = NM_MODEM_MANAGER (user_data); + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->ofono.cancellable); + + if (!results) { + _LOGW ("failed to enumerate oFono devices: %s", + error->message); + return; } + + g_variant_get (results, "(a(oa{sv}))", &iter); + while (g_variant_iter_loop (iter, "(&oa{sv})", &path, NULL)) + ofono_create_modem (self, path); + g_variant_iter_free (iter); + g_variant_unref (results); } static void -ofono_check_name_owner (NMModemManager *self) +ofono_check_name_owner (NMModemManager *self, gboolean first_invocation) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); gs_free char *name_owner = NULL; - name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (self->_priv.ofono_proxy)); + name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (priv->ofono.proxy)); if (name_owner) { - nm_log_info (LOGD_MB, "oFono is now available"); + _LOGI ("oFono is %savailable", first_invocation ? "" : "now "); + + nm_clear_g_cancellable (&priv->ofono.cancellable); + priv->ofono.cancellable = g_cancellable_new (); - g_dbus_proxy_call (self->_priv.ofono_proxy, + g_dbus_proxy_call (priv->ofono.proxy, "GetModems", NULL, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - (GAsyncReadyCallback) ofono_enumerate_devices_done, - g_object_ref (self)); + priv->ofono.cancellable, + ofono_enumerate_devices_done, + self); } else { GHashTableIter iter; NMModem *modem; - nm_log_info (LOGD_MB, "oFono disappeared from bus"); + _LOGI ("oFono is %savailable", first_invocation ? "not " : "no longer "); /* Remove any oFono modems that might be left around */ - g_hash_table_iter_init (&iter, self->_priv.modems); + g_hash_table_iter_init (&iter, priv->modems); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &modem)) { if (NM_IS_MODEM_OFONO (modem)) { nm_modem_emit_removed (modem); @@ -344,219 +716,121 @@ ofono_name_owner_changed (GDBusProxy *ofono_proxy, GParamSpec *pspec, NMModemManager *self) { - ofono_check_name_owner (self); + ofono_check_name_owner (self, FALSE); } static void -ofono_proxy_new_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +ofono_proxy_new_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { - gs_unref_object NMModemManager *self = NM_MODEM_MANAGER (user_data); + NMModemManager *self; + NMModemManagerPrivate *priv; gs_free_error GError *error = NULL; + GDBusProxy *proxy; - self->_priv.ofono_proxy = g_dbus_proxy_new_finish (res, &error); - if (error) { - nm_log_warn (LOGD_MB, "error getting oFono bus proxy: %s", error->message); + proxy = g_dbus_proxy_new_finish (res, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_MANAGER (user_data); + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->ofono.cancellable); + + if (!proxy) { + _LOGW ("error getting oFono bus proxy: %s", error->message); return; } - g_signal_connect (self->_priv.ofono_proxy, + priv->ofono.proxy = proxy; + + g_signal_connect (priv->ofono.proxy, "notify::g-name-owner", G_CALLBACK (ofono_name_owner_changed), self); - g_signal_connect (self->_priv.ofono_proxy, + g_signal_connect (priv->ofono.proxy, "g-signal", G_CALLBACK (ofono_signal_cb), self); - ofono_check_name_owner (self); + ofono_check_name_owner (self, TRUE); } static void -ensure_ofono_client (NMModemManager *self) +ofono_init_proxy (NMModemManager *self) { - g_assert (self->_priv.dbus_connection); - g_dbus_proxy_new (self->_priv.dbus_connection, + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + nm_assert (priv->dbus_connection); + nm_assert (!priv->ofono.cancellable); + + priv->ofono.cancellable = g_cancellable_new (); + + g_dbus_proxy_new (priv->dbus_connection, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, OFONO_DBUS_SERVICE, OFONO_DBUS_PATH, OFONO_DBUS_INTERFACE, - NULL, - (GAsyncReadyCallback) ofono_proxy_new_cb, - g_object_ref (self)); + priv->ofono.cancellable, + ofono_proxy_new_cb, + self); } #endif -static void -modem_manager_poke_cb (GDBusConnection *connection, - GAsyncResult *res, - NMModemManager *self) -{ - GError *error = NULL; - GVariant *result; - - result = g_dbus_connection_call_finish (connection, res, &error); - if (error) { - nm_log_warn (LOGD_MB, "error poking ModemManager: %s", - error ? error->message : ""); - - /* Don't reschedule poke is MM service doesn't exist. */ - if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) - && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) { - - /* Setup timeout to relaunch */ - schedule_modem_manager_relaunch (self, MODEM_POKE_INTERVAL); - } - - g_error_free (error); - } else - g_variant_unref (result); - - /* Balance refcount */ - g_object_unref (self); -} - -static void -modem_manager_poke (NMModemManager *self) -{ - /* If there is no current owner right away, ensure we poke to get one */ - g_dbus_connection_call (self->_priv.dbus_connection, - "org.freedesktop.ModemManager1", - "/org/freedesktop/ModemManager1", - DBUS_INTERFACE_PEER, - "Ping", - NULL, /* inputs */ - NULL, /* outputs */ - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* cancellable */ - (GAsyncReadyCallback)modem_manager_poke_cb, /* callback */ - g_object_ref (self)); /* user_data */ -} +/*****************************************************************************/ static void -modem_manager_check_name_owner (NMModemManager *self) +bus_get_ready (GObject *source, + GAsyncResult *res, + gpointer user_data) { - gs_free gchar *name_owner = NULL; + NMModemManager *self; + NMModemManagerPrivate *priv; + gs_free_error GError *error = NULL; + GDBusConnection *connection; - name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (self->_priv.modem_manager)); - if (name_owner) { - /* Available! */ - modem_manager_available (self); + connection = g_bus_get_finish (res, &error); + if ( !connection + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } - - /* If the lifecycle is not managed by systemd, poke */ - if (!sd_booted ()) - modem_manager_poke (self); -} - -static void -manager_new_ready (GObject *source, - GAsyncResult *res, - NMModemManager *self) -{ - /* Note we always get an extra reference to self here */ - GError *error = NULL; + self = NM_MODEM_MANAGER (user_data); + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); - g_return_if_fail (!self->_priv.modem_manager); - - self->_priv.modem_manager = mm_manager_new_finish (res, &error); - if (!self->_priv.modem_manager) { - /* We're not really supposed to get any error here. If we do get one, - * though, just re-schedule the MMManager creation after some time. - * During this period, name-owner changes won't be followed. */ - nm_log_warn (LOGD_MB, "error creating ModemManager client: %s", error->message); - g_error_free (error); - /* Setup timeout to relaunch */ - schedule_modem_manager_relaunch (self, MODEM_POKE_INTERVAL); - } else { - /* Setup signals in the GDBusObjectManagerClient */ - self->_priv.mm_name_owner_changed_id = - g_signal_connect (self->_priv.modem_manager, - "notify::name-owner", - G_CALLBACK (modem_manager_name_owner_changed), - self); - self->_priv.mm_object_added_id = - g_signal_connect (self->_priv.modem_manager, - "object-added", - G_CALLBACK (modem_object_added), - self); - self->_priv.mm_object_removed_id = - g_signal_connect (self->_priv.modem_manager, - "object-removed", - G_CALLBACK (modem_object_removed), - self); - - modem_manager_check_name_owner (self); - } - - /* Balance refcount */ - g_object_unref (self); -} - -static void -ensure_modem_manager (NMModemManager *self) -{ - g_assert (self->_priv.dbus_connection); - - /* Create the GDBusObjectManagerClient. We do not request to autostart, as - * we don't really want the MMManager creation to fail. We can always poke - * later on if we want to request the autostart */ - if (!self->_priv.modem_manager) { - mm_manager_new (self->_priv.dbus_connection, - G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, - NULL, - (GAsyncReadyCallback)manager_new_ready, - g_object_ref (self)); + if (!connection) { + _LOGW ("error getting bus connection: %s", error->message); return; } - /* If already available, recheck name owner! */ - modem_manager_check_name_owner (self); -} + priv->dbus_connection = connection; -static gboolean -mm_launch_cb (NMModemManager *self) -{ - self->_priv.mm_launch_id = 0; - ensure_modem_manager (self); - return G_SOURCE_REMOVE; + modm_ensure_manager (self); +#if WITH_OFONO + ofono_init_proxy (self); +#endif } -static void -schedule_modem_manager_relaunch (NMModemManager *self, - guint n_seconds) -{ - /* No need to pass an extra reference to self; timeout/idle will be - * cancelled if the object gets disposed. */ - if (n_seconds) - self->_priv.mm_launch_id = g_timeout_add_seconds (n_seconds, (GSourceFunc)mm_launch_cb, self); - else - self->_priv.mm_launch_id = g_idle_add ((GSourceFunc)mm_launch_cb, self); -} +/*****************************************************************************/ static void -bus_get_ready (GObject *source, - GAsyncResult *res, - gpointer user_data) +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) { - gs_unref_object NMModemManager *self = NM_MODEM_MANAGER (user_data); - gs_free_error GError *error = NULL; - - self->_priv.dbus_connection = g_bus_get_finish (res, &error); - if (!self->_priv.dbus_connection) { - nm_log_warn (LOGD_MB, "error getting bus connection: %s", error->message); - return; + NMModemManager *self = NM_MODEM_MANAGER (object); + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + switch (prop_id) { + case PROP_NAME_OWNER: + g_value_set_string (value, priv->modm.proxy_name_owner); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } - - /* Got the bus, ensure clients */ - ensure_modem_manager (self); -#if WITH_OFONO - ensure_ofono_client (self); -#endif } /*****************************************************************************/ @@ -564,36 +838,50 @@ bus_get_ready (GObject *source, static void nm_modem_manager_init (NMModemManager *self) { - self->_priv.modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + priv->modems = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref); + + priv->main_cancellable = g_cancellable_new (); g_bus_get (G_BUS_TYPE_SYSTEM, - NULL, - (GAsyncReadyCallback)bus_get_ready, - g_object_ref (self)); + priv->main_cancellable, + bus_get_ready, + self); } static void dispose (GObject *object) { NMModemManager *self = NM_MODEM_MANAGER (object); + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); - nm_clear_g_source (&self->_priv.mm_launch_id); + nm_clear_g_cancellable (&priv->main_cancellable); + nm_clear_g_cancellable (&priv->modm.poke_cancellable); - clear_modem_manager (self); + nm_clear_g_source (&priv->modm.relaunch_id); + + nm_clear_g_cancellable (&priv->modm.proxy_cancellable); + g_clear_object (&priv->modm.proxy); + nm_clear_g_free (&priv->modm.proxy_name_owner); + + modm_clear_manager (self); #if WITH_OFONO - if (self->_priv.ofono_proxy) { - g_signal_handlers_disconnect_by_func (self->_priv.ofono_proxy, ofono_name_owner_changed, self); - g_signal_handlers_disconnect_by_func (self->_priv.ofono_proxy, ofono_signal_cb, self); - g_clear_object (&self->_priv.ofono_proxy); + if (priv->ofono.proxy) { + g_signal_handlers_disconnect_by_func (priv->ofono.proxy, ofono_name_owner_changed, self); + g_signal_handlers_disconnect_by_func (priv->ofono.proxy, ofono_signal_cb, self); + g_clear_object (&priv->ofono.proxy); } + nm_clear_g_cancellable (&priv->ofono.cancellable); #endif - g_clear_object (&self->_priv.dbus_connection); + g_clear_object (&priv->dbus_connection); - if (self->_priv.modems) { - g_hash_table_foreach_remove (self->_priv.modems, remove_one_modem, object); - g_hash_table_destroy (self->_priv.modems); + if (priv->modems) { + g_hash_table_foreach_remove (priv->modems, remove_one_modem, object); + g_hash_table_destroy (priv->modems); + priv->modems = NULL; } G_OBJECT_CLASS (nm_modem_manager_parent_class)->dispose (object); @@ -605,6 +893,15 @@ nm_modem_manager_class_init (NMModemManagerClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = dispose; + object_class->get_property = get_property; + + obj_properties[PROP_NAME_OWNER] = + g_param_spec_string (NM_MODEM_MANAGER_NAME_OWNER, "", "", + NULL, + G_PARAM_READABLE + | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[MODEM_ADDED] = g_signal_new (NM_MODEM_MANAGER_MODEM_ADDED, diff --git a/src/devices/wwan/nm-modem-manager.h b/src/devices/wwan/nm-modem-manager.h index 65594dfa..5f913083 100644 --- a/src/devices/wwan/nm-modem-manager.h +++ b/src/devices/wwan/nm-modem-manager.h @@ -34,9 +34,22 @@ #define NM_MODEM_MANAGER_MODEM_ADDED "modem-added" +#define NM_MODEM_MANAGER_NAME_OWNER "name-owner" + +#define NM_MODEM_MANAGER_MM_DBUS_SERVICE "org.freedesktop.ModemManager1" +#define NM_MODEM_MANAGER_MM_DBUS_PATH "/org/freedesktop/ModemManager1" +#define NM_MODEM_MANAGER_MM_DBUS_INTERFACE "org.freedesktop.ModemManager1" + typedef struct _NMModemManager NMModemManager; typedef struct _NMModemManagerClass NMModemManagerClass; GType nm_modem_manager_get_type (void); +NMModemManager *nm_modem_manager_get (void); + +void nm_modem_manager_name_owner_ref (NMModemManager *self); +void nm_modem_manager_name_owner_unref (NMModemManager *self); + +const char *nm_modem_manager_name_owner_get (NMModemManager *self); + #endif /* __NETWORKMANAGER_MODEM_MANAGER_H__ */ diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 52b335c7..8b3fc2e8 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -46,6 +46,11 @@ typedef struct { GDBusProxy *context_proxy; GDBusProxy *sim_proxy; + GCancellable *modem_proxy_cancellable; + GCancellable *connman_proxy_cancellable; + GCancellable *context_proxy_cancellable; + GCancellable *sim_proxy_cancellable; + GError *property_error; char *context_path; @@ -99,22 +104,6 @@ G_DEFINE_TYPE (NMModemOfono, nm_modem_ofono, NM_TYPE_MODEM) /*****************************************************************************/ -static gboolean -ip_string_to_network_address (const gchar *str, - guint32 *out) -{ - guint32 addr = 0; - gboolean success = FALSE; - - if (!str || inet_pton (AF_INET, str, &addr) != 1) - addr = 0; - else - success = TRUE; - - *out = (guint32)addr; - return success; -} - static void get_capabilities (NMModem *_self, NMDeviceModemCapabilities *modem_caps, @@ -165,29 +154,17 @@ typedef struct { static void disconnect_context_complete (DisconnectContext *ctx) { - g_simple_async_result_complete_in_idle (ctx->result); if (ctx->cancellable) g_object_unref (ctx->cancellable); - g_object_unref (ctx->result); + if (ctx->result) { + g_simple_async_result_complete_in_idle (ctx->result); + g_object_unref (ctx->result); + } g_object_unref (ctx->self); g_slice_free (DisconnectContext, ctx); } static gboolean -disconnect_context_complete_if_cancelled (DisconnectContext *ctx) -{ - GError *error = NULL; - - if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) { - g_simple_async_result_take_error (ctx->result, error); - disconnect_context_complete (ctx); - return TRUE; - } - - return FALSE; -} - -static gboolean disconnect_finish (NMModem *self, GAsyncResult *result, GError **error) @@ -196,25 +173,25 @@ disconnect_finish (NMModem *self, } static void -disconnect_done (GDBusProxy *proxy, - GAsyncResult *result, - gpointer user_data) +disconnect_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { DisconnectContext *ctx = (DisconnectContext*) user_data; NMModemOfono *self = ctx->self; - GError *error = NULL; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v = NULL; - g_dbus_proxy_call_finish (proxy, result, &error); + v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - _LOGD ("disconnect cancelled"); + if (ctx->result) + g_simple_async_result_take_error (ctx->result, g_steal_pointer (&error)); + disconnect_context_complete (ctx); return; } - if (error) { - if (ctx->warn) - _LOGW ("failed to disconnect modem: %s", error->message); - g_clear_error (&error); - } + if (error && ctx->warn) + _LOGW ("failed to disconnect modem: %s", error->message); _LOGD ("modem disconnected"); @@ -233,18 +210,15 @@ disconnect (NMModem *modem, NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); DisconnectContext *ctx; NMModemState state = nm_modem_get_state (NM_MODEM (self)); + GError *error = NULL; _LOGD ("warn: %s modem_state: %s", warn ? "TRUE" : "FALSE", nm_modem_state_to_string (state)); - if (state != NM_MODEM_STATE_CONNECTED) - return; - - ctx = g_slice_new (DisconnectContext); + ctx = g_slice_new0 (DisconnectContext); ctx->self = g_object_ref (self); ctx->warn = warn; - if (callback) { ctx->result = g_simple_async_result_new (G_OBJECT (self), callback, @@ -252,9 +226,28 @@ disconnect (NMModem *modem, disconnect); } - ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - if (disconnect_context_complete_if_cancelled (ctx)) + if (state != NM_MODEM_STATE_CONNECTED) { + if (ctx->result) { + g_set_error_literal (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + ("modem is currently not connected")); + g_simple_async_result_take_error (ctx->result, error); + } + disconnect_context_complete (ctx); return; + } + + if (g_cancellable_set_error_if_cancelled (cancellable, &error)) { + if (ctx->result) + g_simple_async_result_take_error (ctx->result, error); + else + g_clear_error (&error); + disconnect_context_complete (ctx); + return; + } + + ctx->cancellable = nm_g_object_ref (cancellable); nm_modem_set_state (NM_MODEM (self), NM_MODEM_STATE_DISCONNECTING, @@ -267,8 +260,8 @@ disconnect (NMModem *modem, g_variant_new ("b", warn)), G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, - (GAsyncReadyCallback) disconnect_done, + ctx->cancellable, + disconnect_done, ctx); } @@ -375,22 +368,35 @@ sim_property_changed (GDBusProxy *proxy, } static void -sim_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +sim_get_properties_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - GError *error = NULL; - GVariant *v_properties, *v_dict, *v; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v_properties = NULL; + gs_unref_variant GVariant *v_dict = NULL; + GVariant *v; GVariantIter i; const char *property; - v_properties = _nm_dbus_proxy_call_finish (proxy, + v_properties = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, G_VARIANT_TYPE ("(a{sv})"), &error); + if ( !v_properties + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + g_clear_object (&priv->sim_proxy_cancellable); + if (!v_properties) { g_dbus_error_strip_remote_error (error); _LOGW ("error getting sim properties: %s", error->message); - g_error_free (error); return; } @@ -418,9 +424,49 @@ sim_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ handle_sim_property (NULL, property, v, self); g_variant_unref (v); } +} - g_variant_unref (v_dict); - g_variant_unref (v_properties); +static void +_sim_proxy_new_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; + + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + if (!proxy) { + _LOGW ("failed to create SimManager proxy: %s", error->message); + g_clear_object (&priv->sim_proxy_cancellable); + return; + } + + priv->sim_proxy = proxy; + + /* Watch for custom ofono PropertyChanged signals */ + _nm_dbus_signal_connect (priv->sim_proxy, + "PropertyChanged", + G_VARIANT_TYPE ("(sv)"), + G_CALLBACK (sim_property_changed), + self); + + g_dbus_proxy_call (priv->sim_proxy, + "GetProperties", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 20000, + priv->sim_proxy_cancellable, + sim_get_properties_done, + self); } static void @@ -430,47 +476,30 @@ handle_sim_iface (NMModemOfono *self, gboolean found) _LOGD ("SimManager interface %sfound", found ? "" : "not "); - if (!found && priv->sim_proxy) { + if (!found && (priv->sim_proxy || priv->sim_proxy_cancellable)) { _LOGI ("SimManager interface disappeared"); - g_signal_handlers_disconnect_by_data (priv->sim_proxy, NM_MODEM_OFONO (self)); - g_clear_object (&priv->sim_proxy); + nm_clear_g_cancellable (&priv->sim_proxy_cancellable); + if (priv->sim_proxy) { + g_signal_handlers_disconnect_by_data (priv->sim_proxy, self); + g_clear_object (&priv->sim_proxy); + } g_clear_pointer (&priv->imsi, g_free); update_modem_state (self); - } else if (found && !priv->sim_proxy) { - GError *error = NULL; - + } else if (found && (!priv->sim_proxy && !priv->sim_proxy_cancellable)) { _LOGI ("found new SimManager interface"); - priv->sim_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, /* GDBusInterfaceInfo */ - OFONO_DBUS_SERVICE, - nm_modem_get_path (NM_MODEM (self)), - OFONO_DBUS_INTERFACE_SIM_MANAGER, - NULL, /* GCancellable */ - &error); - if (priv->sim_proxy == NULL) { - _LOGW ("failed to create SimManager proxy: %s", error->message); - g_error_free (error); - return; - } - - /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect (priv->sim_proxy, - "PropertyChanged", - G_VARIANT_TYPE ("(sv)"), - G_CALLBACK (sim_property_changed), - self); - - g_dbus_proxy_call (priv->sim_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - NULL, - (GAsyncReadyCallback) sim_get_properties_done, - g_object_ref (self)); + priv->sim_proxy_cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, /* GDBusInterfaceInfo */ + OFONO_DBUS_SERVICE, + nm_modem_get_path (NM_MODEM (self)), + OFONO_DBUS_INTERFACE_SIM_MANAGER, + priv->sim_proxy_cancellable, /* GCancellable */ + _sim_proxy_new_cb, + self); } } @@ -514,22 +543,35 @@ connman_property_changed (GDBusProxy *proxy, } static void -connman_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +connman_get_properties_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - GError *error = NULL; - GVariant *v_properties, *v_dict, *v; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v_properties = NULL; + gs_unref_variant GVariant *v_dict = NULL; + GVariant *v; GVariantIter i; const char *property; - v_properties = _nm_dbus_proxy_call_finish (proxy, - result, - G_VARIANT_TYPE ("(a{sv})"), - &error); + v_properties = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), + result, + G_VARIANT_TYPE ("(a{sv})"), + &error); + if ( !v_properties + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + g_clear_object (&priv->connman_proxy_cancellable); + if (!v_properties) { g_dbus_error_strip_remote_error (error); _LOGW ("error getting connman properties: %s", error->message); - g_error_free (error); return; } @@ -549,9 +591,48 @@ connman_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer u handle_connman_property (NULL, property, v, self); g_variant_unref (v); } +} + +static void +_connman_proxy_new_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; - g_variant_unref (v_dict); - g_variant_unref (v_properties); + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + if (!proxy) { + _LOGW ("failed to create ConnectionManager proxy: %s", error->message); + g_clear_object (&priv->connman_proxy_cancellable); + return; + } + + priv->connman_proxy = proxy; + + _nm_dbus_signal_connect (priv->connman_proxy, + "PropertyChanged", + G_VARIANT_TYPE ("(sv)"), + G_CALLBACK (connman_property_changed), + self); + + g_dbus_proxy_call (priv->connman_proxy, + "GetProperties", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 20000, + priv->connman_proxy_cancellable, + connman_get_properties_done, + self); } static void @@ -561,11 +642,13 @@ handle_connman_iface (NMModemOfono *self, gboolean found) _LOGD ("ConnectionManager interface %sfound", found ? "" : "not "); - if (!found && priv->connman_proxy) { + if (!found && (priv->connman_proxy || priv->connman_proxy_cancellable)) { _LOGI ("ConnectionManager interface disappeared"); - - g_signal_handlers_disconnect_by_data (priv->connman_proxy, NM_MODEM_OFONO (self)); - g_clear_object (&priv->connman_proxy); + nm_clear_g_cancellable (&priv->connman_proxy_cancellable); + if (priv->connman_proxy) { + g_signal_handlers_disconnect_by_data (priv->connman_proxy, self); + g_clear_object (&priv->connman_proxy); + } /* The connection manager proxy disappeared, we should * consider the modem disabled. @@ -573,41 +656,21 @@ handle_connman_iface (NMModemOfono *self, gboolean found) priv->gprs_attached = FALSE; update_modem_state (self); - } else if (found && !priv->connman_proxy) { - GError *error = NULL; - + } else if (found && (!priv->connman_proxy && !priv->connman_proxy_cancellable)) { _LOGI ("found new ConnectionManager interface"); - priv->connman_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, /* GDBusInterfaceInfo */ - OFONO_DBUS_SERVICE, - nm_modem_get_path (NM_MODEM (self)), - OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, - NULL, /* GCancellable */ - &error); - if (priv->connman_proxy == NULL) { - _LOGW ("failed to create ConnectionManager proxy: %s", error->message); - g_error_free (error); - return; - } - - /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect (priv->connman_proxy, - "PropertyChanged", - G_VARIANT_TYPE ("(sv)"), - G_CALLBACK (connman_property_changed), - self); - - g_dbus_proxy_call (priv->connman_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - NULL, - (GAsyncReadyCallback) connman_get_properties_done, - g_object_ref (self)); + priv->connman_proxy_cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, /* GDBusInterfaceInfo */ + OFONO_DBUS_SERVICE, + nm_modem_get_path (NM_MODEM (self)), + OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, + priv->connman_proxy_cancellable, + _connman_proxy_new_cb, + NULL); } } @@ -667,22 +730,35 @@ modem_property_changed (GDBusProxy *proxy, } static void -modem_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +modem_get_properties_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - GError *error = NULL; - GVariant *v_properties, *v_dict, *v; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v_properties = NULL; + gs_unref_variant GVariant *v_dict = NULL; + GVariant *v; GVariantIter i; const char *property; - v_properties = _nm_dbus_proxy_call_finish (proxy, + v_properties = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, G_VARIANT_TYPE ("(a{sv})"), &error); + if ( !v_properties + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + g_clear_object (&priv->modem_proxy_cancellable); + if (!v_properties) { g_dbus_error_strip_remote_error (error); _LOGW ("error getting modem properties: %s", error->message); - g_error_free (error); return; } @@ -706,21 +782,29 @@ modem_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer use handle_modem_property (NULL, property, v, self); g_variant_unref (v); } - - g_variant_unref (v_dict); - g_variant_unref (v_properties); } static void -stage1_prepare_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +stage1_prepare_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - GError *error = NULL; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v = NULL; + + v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + g_clear_object (&priv->context_proxy_cancellable); g_clear_pointer (&priv->connect_properties, g_hash_table_destroy); - g_dbus_proxy_call_finish (proxy, result, &error); if (error) { _LOGW ("connection failed: %s", error->message); @@ -732,8 +816,6 @@ stage1_prepare_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data * leading to the connection being disabled, and a 5m * timeout... */ - - g_clear_error (&error); } } @@ -751,6 +833,7 @@ context_property_changed (GDBusProxy *proxy, const gchar *s, *addr_s; const gchar **array, **iter; guint32 address_network, gateway_network; + guint32 ip4_route_table, ip4_route_metric; guint prefix = 0; _LOGD ("PropertyChanged: %s", property); @@ -809,15 +892,20 @@ context_property_changed (GDBusProxy *proxy, * 'Interface'. * * This needs discussion with upstream. + * + * FIXME: it is no longer allowed to omit the ifindex for NMIP4Config instances. + * This is broken. */ - priv->ip4_config = nm_ip4_config_new (0); + priv->ip4_config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), + 0); /* TODO: simply if/else error logic! */ if (g_variant_lookup (v_dict, "Address", "&s", &addr_s)) { _LOGD ("Address: %s", addr_s); - if (ip_string_to_network_address (addr_s, &address_network)) { + if ( addr_s + && nm_utils_parse_inaddr_bin (AF_INET, addr_s, &address_network)) { addr.address = address_network; addr.addr_source = NM_IP_CONFIG_SOURCE_WWAN; } else { @@ -833,7 +921,8 @@ context_property_changed (GDBusProxy *proxy, if (g_variant_lookup (v_dict, "Netmask", "&s", &s)) { _LOGD ("Netmask: %s", s); - if (s && ip_string_to_network_address (s, &address_network)) { + if ( s + && nm_utils_parse_inaddr_bin (AF_INET, s, &address_network)) { prefix = nm_utils_ip4_netmask_to_prefix (address_network); if (prefix > 0) addr.plen = prefix; @@ -850,15 +939,30 @@ context_property_changed (GDBusProxy *proxy, nm_ip4_config_add_address (priv->ip4_config, &addr); - if (g_variant_lookup (v_dict, "Gateway", "&s", &s)) { - if (s && ip_string_to_network_address (s, &gateway_network)) { - _LOGI ("Gateway: %s", s); - nm_ip4_config_set_gateway (priv->ip4_config, gateway_network); - } else { + if ( g_variant_lookup (v_dict, "Gateway", "&s", &s) + && s) { + + if (!nm_utils_parse_inaddr_bin (AF_INET, s, &gateway_network)) { _LOGW ("invalid 'Gateway': %s", s); goto out; } - nm_ip4_config_set_gateway (priv->ip4_config, gateway_network); + + nm_modem_get_route_parameters (NM_MODEM (self), + &ip4_route_table, + &ip4_route_metric, + NULL, + NULL); + { + const NMPlatformIP4Route r = { + .rt_source = NM_IP_CONFIG_SOURCE_WWAN, + .gateway = gateway_network, + .table_coerced = nm_platform_route_table_coerce (ip4_route_table), + .metric = ip4_route_metric, + }; + + _LOGI ("Gateway: %s", s); + nm_ip4_config_add_route (priv->ip4_config, &r, NULL); + } } else { _LOGW ("Settings 'Gateway' missing"); goto out; @@ -867,7 +971,8 @@ context_property_changed (GDBusProxy *proxy, if (g_variant_lookup (v_dict, "DomainNameServers", "^a&s", &array)) { if (array) { for (iter = array; *iter; iter++) { - if (ip_string_to_network_address (*iter, &address_network) && address_network > 0) { + if ( nm_utils_parse_inaddr_bin (AF_INET, *iter, &address_network) + && address_network) { _LOGI ("DNS: %s", *iter); nm_ip4_config_add_nameserver (priv->ip4_config, address_network); } else { @@ -889,16 +994,25 @@ context_property_changed (GDBusProxy *proxy, if (g_variant_lookup (v_dict, "MessageProxy", "&s", &s)) { _LOGI ("MessageProxy: %s", s); - if (s && ip_string_to_network_address (s, &address_network)) { - NMPlatformIP4Route mms_route; - - mms_route.network = address_network; - mms_route.plen = 32; - mms_route.gateway = gateway_network; - - mms_route.metric = 1; - - nm_ip4_config_add_route (priv->ip4_config, &mms_route); + if ( s + && nm_utils_parse_inaddr_bin (AF_INET, s, &address_network)) { + nm_modem_get_route_parameters (NM_MODEM (self), + &ip4_route_table, + &ip4_route_metric, + NULL, + NULL); + + { + const NMPlatformIP4Route mms_route = { + .network = address_network, + .plen = 32, + .gateway = gateway_network, + .table_coerced = nm_platform_route_table_coerce (ip4_route_table), + .metric = ip4_route_metric, + }; + + nm_ip4_config_add_route (priv->ip4_config, &mms_route, NULL); + } } else { _LOGW ("invalid MessageProxy: %s", s); } @@ -946,21 +1060,33 @@ static_stage3_ip4_config_start (NMModem *modem, } static void -context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +context_proxy_new_cb (GObject *source, GAsyncResult *result, gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - GError *error = NULL; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; - priv->context_proxy = g_dbus_proxy_new_for_bus_finish (result, &error); - if (error) { + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + if (!proxy) { _LOGE ("failed to create ofono ConnectionContext DBus proxy: %s", error->message); + g_clear_object (&priv->context_proxy_cancellable); nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); return; } + priv->context_proxy = proxy; + if (!priv->gprs_attached) { + g_clear_object (&priv->context_proxy_cancellable); nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); return; @@ -972,7 +1098,6 @@ context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat */ g_clear_object (&priv->ip4_config); - /* Watch for custom ofono PropertyChanged signals */ _nm_dbus_signal_connect (priv->context_proxy, "PropertyChanged", G_VARIANT_TYPE ("(sv)"), @@ -986,9 +1111,9 @@ context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat g_variant_new ("b", TRUE)), G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, - (GAsyncReadyCallback) stage1_prepare_done, - g_object_ref (self)); + priv->context_proxy_cancellable, + stage1_prepare_done, + self); } static void @@ -998,16 +1123,20 @@ do_context_activate (NMModemOfono *self) g_return_if_fail (NM_IS_MODEM_OFONO (self)); + nm_clear_g_cancellable (&priv->context_proxy_cancellable); g_clear_object (&priv->context_proxy); + + priv->context_proxy_cancellable = g_cancellable_new (); + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, OFONO_DBUS_SERVICE, priv->context_path, OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, - NULL, - (GAsyncReadyCallback) context_proxy_new_cb, - g_object_ref (self)); + priv->context_proxy_cancellable, + context_proxy_new_cb, + self); } static GHashTable * @@ -1018,7 +1147,7 @@ create_connect_properties (NMConnection *connection) const char *str; setting = nm_connection_get_setting_gsm (connection); - properties = g_hash_table_new (g_str_hash, g_str_equal); + properties = g_hash_table_new (nm_str_hash, g_str_equal); str = nm_setting_gsm_get_apn (setting); if (str) @@ -1081,19 +1210,29 @@ act_stage1_prepare (NMModem *modem, } static void -modem_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +modem_proxy_new_cb (GObject *source, GAsyncResult *result, gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - GError *error = NULL; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; - priv->modem_proxy = g_dbus_proxy_new_for_bus_finish (result, &error); - if (error) { + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + if (!proxy) { _LOGE ("failed to create ofono modem DBus proxy: %s", error->message); + g_clear_object (&priv->modem_proxy_cancellable); return; } - /* Watch for custom ofono PropertyChanged signals */ + priv->modem_proxy = proxy; + _nm_dbus_signal_connect (priv->modem_proxy, "PropertyChanged", G_VARIANT_TYPE ("(sv)"), @@ -1105,9 +1244,9 @@ modem_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) NULL, G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, - (GAsyncReadyCallback) modem_get_properties_done, - g_object_ref (self)); + priv->modem_proxy_cancellable, + modem_get_properties_done, + self); } /*****************************************************************************/ @@ -1121,6 +1260,9 @@ static void constructed (GObject *object) { NMModemOfono *self = NM_MODEM_OFONO (object); + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + priv->modem_proxy_cancellable = g_cancellable_new (); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, @@ -1128,9 +1270,11 @@ constructed (GObject *object) OFONO_DBUS_SERVICE, nm_modem_get_path (NM_MODEM (self)), OFONO_DBUS_INTERFACE_MODEM, - NULL, - (GAsyncReadyCallback) modem_proxy_new_cb, - g_object_ref (self)); + priv->modem_proxy_cancellable, + modem_proxy_new_cb, + self); + + G_OBJECT_CLASS (nm_modem_ofono_parent_class)->constructed (object); } NMModem * @@ -1163,6 +1307,11 @@ dispose (GObject *object) NMModemOfono *self = NM_MODEM_OFONO (object); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); + nm_clear_g_cancellable (&priv->modem_proxy_cancellable); + nm_clear_g_cancellable (&priv->connman_proxy_cancellable); + nm_clear_g_cancellable (&priv->context_proxy_cancellable); + nm_clear_g_cancellable (&priv->sim_proxy_cancellable); + if (priv->connect_properties) { g_hash_table_destroy (priv->connect_properties); priv->connect_properties = NULL; @@ -1171,15 +1320,22 @@ dispose (GObject *object) g_clear_object (&priv->ip4_config); if (priv->modem_proxy) { - g_signal_handlers_disconnect_by_data (priv->modem_proxy, NM_MODEM_OFONO (self)); + g_signal_handlers_disconnect_by_data (priv->modem_proxy, self); g_clear_object (&priv->modem_proxy); } - g_clear_object (&priv->connman_proxy); - g_clear_object (&priv->context_proxy); + if (priv->connman_proxy) { + g_signal_handlers_disconnect_by_data (priv->connman_proxy, self); + g_clear_object (&priv->connman_proxy); + } + + if (priv->context_proxy) { + g_signal_handlers_disconnect_by_data (priv->context_proxy, self); + g_clear_object (&priv->context_proxy); + } if (priv->sim_proxy) { - g_signal_handlers_disconnect_by_data (priv->sim_proxy, NM_MODEM_OFONO (self)); + g_signal_handlers_disconnect_by_data (priv->sim_proxy, self); g_clear_object (&priv->sim_proxy); } diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 6494b849..77495b62 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -26,13 +26,13 @@ #include <fcntl.h> #include <string.h> #include <termios.h> +#include <linux/rtnetlink.h> #include "nm-core-internal.h" #include "platform/nm-platform.h" #include "nm-setting-connection.h" #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" -#include "nm-route-manager.h" #include "nm-netns.h" #include "nm-act-request.h" #include "nm-ip4-config.h" @@ -98,6 +98,11 @@ typedef struct _NMModemPrivate { guint32 mm_ip_timeout; + guint32 ip4_route_table; + guint32 ip4_route_metric; + guint32 ip6_route_table; + guint32 ip6_route_metric; + /* PPP stats */ guint32 in_bytes; guint32 out_bytes; @@ -108,6 +113,46 @@ G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT) #define NM_MODEM_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR (self, NMModem, NM_IS_MODEM) /*****************************************************************************/ + +#define _NMLOG_PREFIX_BUFLEN 64 +#define _NMLOG_PREFIX_NAME "modem" +#define _NMLOG_DOMAIN LOGD_MB + +static const char * +_nmlog_prefix (char *prefix, NMModem *self) +{ + const char *uuid; + int c; + + if (!self) + return ""; + + uuid = nm_modem_get_uid (self); + + if (uuid) { + char pp[_NMLOG_PREFIX_BUFLEN - 5]; + + c = g_snprintf (prefix, _NMLOG_PREFIX_BUFLEN, "[%s]", + nm_strquote (pp, sizeof (pp), uuid)); + } else + c = g_snprintf (prefix, _NMLOG_PREFIX_BUFLEN, "[%p]", self); + nm_assert (c < _NMLOG_PREFIX_BUFLEN); + + return prefix; +} + +#define _NMLOG(level, ...) \ + G_STMT_START { \ + char _prefix[_NMLOG_PREFIX_BUFLEN]; \ + \ + nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + _nmlog_prefix (_prefix, (self)) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } G_STMT_END + +/*****************************************************************************/ /* State/enabled/connected */ static const char *state_table[] = { @@ -151,11 +196,10 @@ nm_modem_set_state (NMModem *self, priv->prev_state = NM_MODEM_STATE_UNKNOWN; if (new_state != old_state) { - nm_log_info (LOGD_MB, "(%s): modem state changed, '%s' --> '%s' (reason: %s)\n", - nm_modem_get_uid (self), - nm_modem_state_to_string (old_state), - nm_modem_state_to_string (new_state), - reason ? reason : "none"); + _LOGI ("modem state changed, '%s' --> '%s' (reason: %s)", + nm_modem_state_to_string (old_state), + nm_modem_state_to_string (new_state), + reason ? reason : "none"); priv->state = new_state; _notify (self, PROP_STATE); @@ -181,24 +225,20 @@ nm_modem_set_mm_enabled (NMModem *self, NMModemState prev_state = priv->state; if (enabled && priv->state >= NM_MODEM_STATE_ENABLING) { - nm_log_dbg (LOGD_MB, "(%s): cannot enable modem: already enabled", - nm_modem_get_uid (self)); + _LOGD ("cannot enable modem: already enabled"); return; } if (!enabled && priv->state <= NM_MODEM_STATE_DISABLING) { - nm_log_dbg (LOGD_MB, "(%s): cannot disable modem: already disabled", - nm_modem_get_uid (self)); + _LOGD ("cannot disable modem: already disabled"); return; } if (priv->state <= NM_MODEM_STATE_INITIALIZING) { - nm_log_dbg (LOGD_MB, "(%s): cannot enable/disable modem: initializing or failed", - nm_modem_get_uid (self)); + _LOGD ("cannot enable/disable modem: initializing or failed"); return; } else if (priv->state == NM_MODEM_STATE_LOCKED) { /* Don't try to enable if the modem is locked since that will fail */ - nm_log_warn (LOGD_MB, "(%s): cannot enable/disable modem: locked", - nm_modem_get_uid (self)); + _LOGW ("cannot enable/disable modem: locked"); /* Try to unlock the modem if it's being enabled */ if (enabled) @@ -468,7 +508,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager, } if (!num || dns_workaround) { - nm_log_warn (LOGD_PPP, "compensating for invalid PPP-provided nameservers"); + _LOGW ("compensating for invalid PPP-provided nameservers"); nm_ip4_config_reset_nameservers (config); nm_ip4_config_add_nameserver (config, good_dns1); nm_ip4_config_add_nameserver (config, good_dns2); @@ -561,9 +601,8 @@ ppp_stage3_ip_config_start (NMModem *self, /* Check if ModemManager requested a specific IP timeout to be used. If 0 reported, * use the default one (30s) */ if (priv->mm_ip_timeout > 0) { - nm_log_info (LOGD_PPP, "(%s): using modem-specified IP timeout: %u seconds", - nm_modem_get_uid (self), - priv->mm_ip_timeout); + _LOGI ("using modem-specified IP timeout: %u seconds", + priv->mm_ip_timeout); ip_timeout = priv->mm_ip_timeout; } @@ -577,12 +616,18 @@ ppp_stage3_ip_config_start (NMModem *self, priv->ppp_manager = nm_ppp_manager_create (priv->data_port, &error); + if (priv->ppp_manager) { + nm_ppp_manager_set_route_parameters (priv->ppp_manager, + priv->ip4_route_table, + priv->ip4_route_metric, + priv->ip6_route_table, + priv->ip6_route_metric); + } + if ( !priv->ppp_manager || !nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, baud_override, &error)) { - nm_log_err (LOGD_PPP, "(%s): error starting PPP: %s", - nm_modem_get_uid (self), - error->message); + _LOGE ("error starting PPP: %s", error->message); g_error_free (error); g_clear_object (&priv->ppp_manager); @@ -621,7 +666,7 @@ nm_modem_stage3_ip4_config_start (NMModem *self, const char *method; NMActStageReturn ret; - nm_log_dbg (LOGD_MB, "ip4_config_start"); + _LOGD ("ip4_config_start"); g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (NM_IS_DEVICE (device), NM_ACT_STAGE_RETURN_FAILURE); @@ -640,9 +685,8 @@ nm_modem_stage3_ip4_config_start (NMModem *self, return NM_ACT_STAGE_RETURN_SUCCESS; if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) != 0) { - nm_log_warn (LOGD_MB | LOGD_IP4, - "(%s): unhandled WWAN IPv4 method '%s'; will fail", - nm_modem_get_uid (self), method); + _LOGW ("unhandled WWAN IPv4 method '%s'; will fail", + method); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -653,15 +697,15 @@ nm_modem_stage3_ip4_config_start (NMModem *self, ret = ppp_stage3_ip_config_start (self, req, out_failure_reason); break; case NM_MODEM_IP_METHOD_STATIC: - nm_log_dbg (LOGD_MB, "MODEM_IP_METHOD_STATIC"); + _LOGD ("MODEM_IP_METHOD_STATIC"); ret = NM_MODEM_GET_CLASS (self)->static_stage3_ip4_config_start (self, req, out_failure_reason); break; case NM_MODEM_IP_METHOD_AUTO: - nm_log_dbg (LOGD_MB, "MODEM_IP_METHOD_AUTO"); + _LOGD ("MODEM_IP_METHOD_AUTO"); ret = device_class->act_stage3_ip4_config_start (device, NULL, out_failure_reason); break; default: - nm_log_info (LOGD_MB, "(%s): IPv4 configuration disabled", nm_modem_get_uid (self)); + _LOGI ("IPv4 configuration disabled"); ret = NM_ACT_STAGE_RETURN_IP_FAIL; break; } @@ -676,13 +720,15 @@ nm_modem_ip4_pre_commit (NMModem *modem, { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (modem); + nm_modem_set_route_parameters_from_device (modem, device); + /* If the modem has an ethernet-type data interface (ie, not PPP and thus * not point-to-point) and IP config has a /32 prefix, then we assume that * ARP will be pointless and we turn it off. */ if ( priv->ip4_method == NM_MODEM_IP_METHOD_STATIC || priv->ip4_method == NM_MODEM_IP_METHOD_AUTO) { - const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, 0); + const NMPlatformIP4Address *address = nm_ip4_config_get_first_address (config); g_assert (address); if (address->plen == 32) @@ -698,7 +744,8 @@ nm_modem_emit_ip6_config_result (NMModem *self, GError *error) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - guint i, num; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *addr; gboolean do_slaac = TRUE; if (error) { @@ -710,11 +757,7 @@ nm_modem_emit_ip6_config_result (NMModem *self, /* If the IPv6 configuration only included a Link-Local address, then * we have to run SLAAC to get the full IPv6 configuration. */ - num = nm_ip6_config_get_num_addresses (config); - g_assert (num > 0); - for (i = 0; i < num; i++) { - const NMPlatformIP6Address * addr = nm_ip6_config_get_address (config, i); - + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, config, &addr) { if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { if (!priv->iid.id) priv->iid.id = ((guint64 *)(&addr->address.s6_addr))[1]; @@ -757,9 +800,8 @@ nm_modem_stage3_ip6_config_start (NMModem *self, return NM_ACT_STAGE_RETURN_IP_DONE; if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) != 0) { - nm_log_warn (LOGD_MB | LOGD_IP6, - "(%s): unhandled WWAN IPv6 method '%s'; will fail", - nm_modem_get_uid (self), method); + _LOGW ("unhandled WWAN IPv6 method '%s'; will fail", + method); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -778,7 +820,7 @@ nm_modem_stage3_ip6_config_start (NMModem *self, ret = NM_MODEM_GET_CLASS (self)->stage3_ip6_config_request (self, out_failure_reason); break; default: - nm_log_info (LOGD_MB, "(%s): IPv6 configuration disabled", nm_modem_get_uid (self)); + _LOGI ("IPv6 configuration disabled"); ret = NM_ACT_STAGE_RETURN_IP_FAIL; break; } @@ -854,7 +896,7 @@ modem_secrets_cb (NMActRequest *req, return; if (error) - nm_log_warn (LOGD_MB, "(%s): %s", nm_modem_get_uid (self), error->message); + _LOGW ("modem-secrets: %s", error->message); g_signal_emit (self, signals[AUTH_RESULT], 0, error); } @@ -975,17 +1017,15 @@ nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection) str = nm_setting_gsm_get_device_id (s_gsm); if (str) { if (!priv->device_id) { - nm_log_dbg (LOGD_MB, "(%s): %s/%s has device-id, device does not", - priv->uid, - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + _LOGD ("%s/%s has device-id, device does not", + nm_connection_get_uuid (connection), + nm_connection_get_id (connection)); return FALSE; } if (strcmp (str, priv->device_id)) { - nm_log_dbg (LOGD_MB, "(%s): %s/%s device-id mismatch", - priv->uid, - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + _LOGD ("%s/%s device-id mismatch", + nm_connection_get_uuid (connection), + nm_connection_get_id (connection)); return FALSE; } } @@ -998,10 +1038,9 @@ nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection) str = nm_setting_gsm_get_sim_id (s_gsm); if (str && priv->sim_id) { if (strcmp (str, priv->sim_id)) { - nm_log_dbg (LOGD_MB, "(%s): %s/%s sim-id mismatch", - priv->uid, - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + _LOGD ("%s/%s sim-id mismatch", + nm_connection_get_uuid (connection), + nm_connection_get_id (connection)); return FALSE; } } @@ -1009,10 +1048,9 @@ nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection) str = nm_setting_gsm_get_sim_operator_id (s_gsm); if (str && priv->sim_operator_id) { if (strcmp (str, priv->sim_operator_id)) { - nm_log_dbg (LOGD_MB, "(%s): %s/%s sim-operator-id mismatch", - priv->uid, - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + _LOGD ("%s/%s sim-operator-id mismatch", + nm_connection_get_uuid (connection), + nm_connection_get_id (connection)); return FALSE; } } @@ -1069,10 +1107,11 @@ deactivate_cleanup (NMModem *self, NMDevice *device) priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) { ifindex = nm_device_get_ip_ifindex (device); if (ifindex > 0) { - nm_route_manager_route_flush (nm_netns_get_route_manager (nm_device_get_netns (device)), - ifindex); - nm_platform_address_flush (nm_device_get_platform (device), ifindex); - nm_platform_link_set_down (nm_device_get_platform (device), ifindex); + NMPlatform *platform = nm_device_get_platform (device); + + nm_platform_ip_route_flush (platform, AF_UNSPEC, ifindex); + nm_platform_ip_address_flush (platform, AF_UNSPEC, ifindex); + nm_platform_link_set_down (platform, ifindex); } } } @@ -1149,12 +1188,12 @@ ppp_manager_stop_ready (NMPPPManager *ppp_manager, GAsyncResult *res, DeactivateContext *ctx) { + NMModem *self = ctx->self; GError *error = NULL; if (!nm_ppp_manager_stop_finish (ppp_manager, res, &error)) { - nm_log_warn (LOGD_MB, "(%s): cannot stop PPP manager: %s", - nm_modem_get_uid (ctx->self), - error->message); + _LOGW ("cannot stop PPP manager: %s", + error->message); g_simple_async_result_take_error (ctx->result, error); deactivate_context_complete (ctx); return; @@ -1168,7 +1207,8 @@ ppp_manager_stop_ready (NMPPPManager *ppp_manager, static void deactivate_step (DeactivateContext *ctx) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (ctx->self); + NMModem *self = ctx->self; + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); GError *error = NULL; /* Check cancellable in each step */ @@ -1187,7 +1227,7 @@ deactivate_step (DeactivateContext *ctx) if (priv->ppp_manager) ctx->ppp_manager = g_object_ref (priv->ppp_manager); /* Run cleanup */ - NM_MODEM_GET_CLASS (ctx->self)->deactivate_cleanup (ctx->self, ctx->device); + NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, ctx->device); ctx->step++; /* fall through */ case DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP: @@ -1203,16 +1243,15 @@ deactivate_step (DeactivateContext *ctx) /* fall through */ case DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT: /* Disconnect asynchronously */ - NM_MODEM_GET_CLASS (ctx->self)->disconnect (ctx->self, - FALSE, - ctx->cancellable, - (GAsyncReadyCallback) disconnect_ready, - ctx); + NM_MODEM_GET_CLASS (self)->disconnect (self, + FALSE, + ctx->cancellable, + (GAsyncReadyCallback) disconnect_ready, + ctx); return; case DEACTIVATE_CONTEXT_STEP_LAST: - nm_log_dbg (LOGD_MB, "(%s): modem deactivation finished", - nm_modem_get_uid (ctx->self)); + _LOGD ("modem deactivation finished"); deactivate_context_complete (ctx); return; } @@ -1377,6 +1416,76 @@ nm_modem_get_iid (NMModem *self, NMUtilsIPv6IfaceId *out_iid) /*****************************************************************************/ void +nm_modem_get_route_parameters (NMModem *self, + guint32 *out_ip4_route_table, + guint32 *out_ip4_route_metric, + guint32 *out_ip6_route_table, + guint32 *out_ip6_route_metric) +{ + NMModemPrivate *priv; + + g_return_if_fail (NM_IS_MODEM (self)); + + priv = NM_MODEM_GET_PRIVATE (self); + NM_SET_OUT (out_ip4_route_table, priv->ip4_route_table); + NM_SET_OUT (out_ip4_route_metric, priv->ip4_route_metric); + NM_SET_OUT (out_ip6_route_table, priv->ip6_route_table); + NM_SET_OUT (out_ip6_route_metric, priv->ip6_route_metric); +} + +void +nm_modem_set_route_parameters (NMModem *self, + guint32 ip4_route_table, + guint32 ip4_route_metric, + guint32 ip6_route_table, + guint32 ip6_route_metric) +{ + NMModemPrivate *priv; + + g_return_if_fail (NM_IS_MODEM (self)); + + priv = NM_MODEM_GET_PRIVATE (self); + if ( priv->ip4_route_table != ip4_route_table + || priv->ip4_route_metric != ip4_route_metric + || priv->ip6_route_table != ip6_route_table + || priv->ip6_route_metric != ip6_route_metric) { + priv->ip4_route_table = ip4_route_table; + priv->ip4_route_metric = ip4_route_metric; + priv->ip6_route_table = ip6_route_table; + priv->ip6_route_metric = ip6_route_metric; + + _LOGT ("route-parameters: table-v4: %u, metric-v4: %u, table-v6: %u, metric-v6: %u", + priv->ip4_route_table, + priv->ip4_route_metric, + priv->ip6_route_table, + priv->ip6_route_metric); + } + + if (priv->ppp_manager) { + nm_ppp_manager_set_route_parameters (priv->ppp_manager, + priv->ip4_route_table, + priv->ip4_route_metric, + priv->ip6_route_table, + priv->ip6_route_metric); + } +} + +void +nm_modem_set_route_parameters_from_device (NMModem *self, + NMDevice *device) +{ + g_return_if_fail (NM_IS_DEVICE (device)); + + nm_modem_set_route_parameters (self, + nm_device_get_route_table (device, AF_INET, TRUE), + nm_device_get_route_metric (device, AF_INET), + nm_device_get_route_table (device, AF_INET6, TRUE), + nm_device_get_route_metric (device, AF_INET6)); +} + +/*****************************************************************************/ + +void nm_modem_get_capabilities (NMModem *self, NMDeviceModemCapabilities *modem_caps, NMDeviceModemCapabilities *current_caps) @@ -1451,6 +1560,7 @@ set_property (GObject *object, guint prop_id, case PROP_PATH: /* construct-only */ priv->path = g_value_dup_string (value); + g_return_if_fail (priv->path); break; case PROP_DRIVER: /* construct-only */ @@ -1509,40 +1619,27 @@ set_property (GObject *object, guint prop_id, static void nm_modem_init (NMModem *self) { + NMModemPrivate *priv; + self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM, NMModemPrivate); + priv = self->_priv; + + priv->ip4_route_table = RT_TABLE_MAIN; + priv->ip4_route_metric = 700; + priv->ip6_route_table = RT_TABLE_MAIN; + priv->ip6_route_metric = 700; } -static GObject* -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) +static void +constructed (GObject *object) { - GObject *object; NMModemPrivate *priv; - object = G_OBJECT_CLASS (nm_modem_parent_class)->constructor (type, - n_construct_params, - construct_params); - if (!object) - return NULL; - - priv = NM_MODEM_GET_PRIVATE ((NMModem *) object); + G_OBJECT_CLASS (nm_modem_parent_class)->constructed (object); - if (!priv->data_port && !priv->control_port) { - nm_log_err (LOGD_PLATFORM, "neither modem command nor data interface provided"); - goto err; - } + priv = NM_MODEM_GET_PRIVATE (NM_MODEM (object)); - if (!priv->path) { - nm_log_err (LOGD_PLATFORM, "D-Bus path not provided"); - goto err; - } - - return object; - -err: - g_object_unref (object); - return NULL; + g_return_if_fail (priv->data_port || priv->control_port); } /*****************************************************************************/ @@ -1552,10 +1649,7 @@ dispose (GObject *object) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE ((NMModem *) object); - if (priv->act_request) { - g_object_unref (priv->act_request); - priv->act_request = NULL; - } + g_clear_object (&priv->act_request); G_OBJECT_CLASS (nm_modem_parent_class)->dispose (object); } @@ -1584,7 +1678,7 @@ nm_modem_class_init (NMModemClass *klass) g_type_class_add_private (object_class, sizeof (NMModemPrivate)); - object_class->constructor = constructor; + object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index a50727a9..9546e4a1 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -105,10 +105,12 @@ typedef enum { /*< underscore_name=nm_modem_state >*/ struct _NMModemPrivate; -typedef struct { +struct _NMModem { GObject parent; struct _NMModemPrivate *_priv; -} NMModem; +}; + +typedef struct _NMModem NMModem; typedef struct { GObjectClass parent; @@ -185,6 +187,21 @@ gboolean nm_modem_complete_connection (NMModem *self, const GSList *existing_connections, GError **error); +void nm_modem_get_route_parameters (NMModem *self, + guint32 *out_ip4_route_table, + guint32 *out_ip4_route_metric, + guint32 *out_ip6_route_table, + guint32 *out_ip6_route_metric); + +void nm_modem_set_route_parameters (NMModem *self, + guint32 ip4_route_table, + guint32 ip4_route_metric, + guint32 ip6_route_table, + guint32 ip6_route_metric); + +void nm_modem_set_route_parameters_from_device (NMModem *modem, + NMDevice *device); + NMActStageReturn nm_modem_act_stage1_prepare (NMModem *modem, NMActRequest *req, NMDeviceStateReason *out_failure_reason); diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index fa4c8dbb..663102de 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -127,8 +127,8 @@ start (NMDeviceFactory *factory) NMWwanFactory *self = NM_WWAN_FACTORY (factory); NMWwanFactoryPrivate *priv = NM_WWAN_FACTORY_GET_PRIVATE (self); - priv->mm = g_object_new (NM_TYPE_MODEM_MANAGER, NULL); - g_assert (priv->mm); + priv->mm = g_object_ref (nm_modem_manager_get ()); + g_signal_connect (priv->mm, NM_MODEM_MANAGER_MODEM_ADDED, G_CALLBACK (modem_added_cb), |