diff options
Diffstat (limited to 'src/devices')
25 files changed, 1376 insertions, 594 deletions
diff --git a/src/devices/adsl/Makefile.in b/src/devices/adsl/Makefile.in index 7942c559..02da85e7 100644 --- a/src/devices/adsl/Makefile.in +++ b/src/devices/adsl/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,8 +89,6 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/devices/adsl -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -207,6 +216,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -233,7 +244,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -268,6 +278,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -524,7 +535,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/adsl/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/devices/adsl/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -596,14 +606,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -831,6 +841,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkglibLTLIBRARIES +.PRECIOUS: Makefile + include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ diff --git a/src/devices/bluetooth/Makefile.in b/src/devices/bluetooth/Makefile.in index 0a285fda..b8e6dcda 100644 --- a/src/devices/bluetooth/Makefile.in +++ b/src/devices/bluetooth/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -85,8 +95,6 @@ host_triplet = @host@ @WITH_BLUEZ5_DUN_TRUE@am__append_3 = $(BLUEZ5_LIBS) subdir = src/devices/bluetooth -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -103,6 +111,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -227,6 +236,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -253,7 +264,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -288,6 +298,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -536,7 +547,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/bluetooth/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/devices/bluetooth/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -614,14 +624,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -849,6 +859,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkglibLTLIBRARIES +.PRECIOUS: Makefile + include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 689f37c9..61371ddd 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -187,6 +187,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) static gboolean check_connection_available (NMDevice *device, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); @@ -929,7 +930,7 @@ bluez_device_removed (NMBluezDevice *bdev, gpointer user_data) /*****************************************************************************/ static gboolean -is_available (NMDevice *dev) +is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags) { NMDeviceBt *self = NM_DEVICE_BT (dev); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); @@ -957,7 +958,7 @@ handle_availability_change (NMDeviceBt *self, return; } - available = nm_device_is_available (device); + available = nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); if (available == old_available) return; @@ -987,7 +988,7 @@ set_mm_running (NMDeviceBt *self, gboolean running) _LOGD (LOGD_BT, "ModemManager now %s", running ? "available" : "unavailable"); - old_available = nm_device_is_available (NM_DEVICE (self)); + old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); priv->mm_running = running; handle_availability_change (self, old_available, NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE); diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 9d9fe426..0b2c97d1 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -67,7 +67,7 @@ get_generic_capabilities (NMDevice *dev) } static gboolean -is_available (NMDevice *dev) +is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags) { if (NM_DEVICE_GET_CLASS (dev)->is_up) return NM_DEVICE_GET_CLASS (dev)->is_up (dev); @@ -77,6 +77,7 @@ is_available (NMDevice *dev) static gboolean check_connection_available (NMDevice *device, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object) { /* Connections are always available because the carrier state is determined diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index a70cfd95..a2ed4b41 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -66,7 +66,7 @@ get_generic_capabilities (NMDevice *dev) } static gboolean -is_available (NMDevice *dev) +is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags) { if (NM_DEVICE_GET_CLASS (dev)->is_up) return NM_DEVICE_GET_CLASS (dev)->is_up (dev); @@ -76,6 +76,7 @@ is_available (NMDevice *dev) static gboolean check_connection_available (NMDevice *device, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object) { /* Connections are always available because the carrier state is determined diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 65a9a71a..1f781bbc 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -33,7 +33,8 @@ enum NMActStageReturn { NM_ACT_STAGE_RETURN_SUCCESS, /* Activation stage done */ NM_ACT_STAGE_RETURN_POSTPONE, /* Long-running operation in progress */ NM_ACT_STAGE_RETURN_WAIT, /* Not ready to start stage; wait */ - NM_ACT_STAGE_RETURN_STOP /* Activation stage done; nothing to do */ + NM_ACT_STAGE_RETURN_STOP, /* Activation not wanted */ + NM_ACT_STAGE_RETURN_FINISH /* Activation stage done; nothing to do */ }; #define NM_DEVICE_CAP_NONSTANDARD_CARRIER 0x80000000 diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index a9899535..47526281 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -201,14 +201,18 @@ typedef struct { char * hw_addr; guint hw_addr_len; char * physical_port_id; + guint dev_id; NMUnmanagedFlags unmanaged_flags; gboolean is_nm_owned; /* whether the device is a device owned and created by NM */ DeleteOnDeactivateData *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */ + GCancellable *deactivating_cancellable; + guint32 ip4_address; NMActRequest * queued_act_request; + gboolean queued_act_request_is_waiting_for_carrier; NMActRequest * act_request; guint act_source_id; gpointer act_source_func; @@ -337,6 +341,8 @@ static gboolean addrconf6_start_with_link_ready (NMDevice *self); static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection); static NMActStageReturn linklocal6_start (NMDevice *self); +static void _carrier_wait_check_queued_act_request (NMDevice *self); + static gboolean nm_device_get_default_unmanaged (NMDevice *self); static void _set_state_full (NMDevice *self, @@ -381,6 +387,7 @@ state_to_string (NMDeviceState state) } static const char *reason_table[] = { + [NM_DEVICE_STATE_REASON_UNKNOWN] = "unknown", [NM_DEVICE_STATE_REASON_NONE] = "none", [NM_DEVICE_STATE_REASON_NOW_MANAGED] = "managed", [NM_DEVICE_STATE_REASON_NOW_UNMANAGED] = "unmanaged", @@ -440,6 +447,7 @@ static const char *reason_table[] = { [NM_DEVICE_STATE_REASON_MODEM_FAILED] = "modem-failed", [NM_DEVICE_STATE_REASON_MODEM_AVAILABLE] = "modem-available", [NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT] = "sim-pin-incorrect", + [NM_DEVICE_STATE_REASON_NEW_ACTIVATION] = "new-activation", }; static const char * @@ -588,6 +596,7 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface) static gboolean get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMLinkType link_type; const guint8 *hwaddr = NULL; size_t hwaddr_len = 0; @@ -608,6 +617,7 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) success = nm_utils_get_ipv6_interface_identifier (link_type, hwaddr, hwaddr_len, + priv->dev_id, out_iid); if (!success) { _LOGW (LOGD_HW, "failed to generate interface identifier " @@ -692,6 +702,8 @@ nm_device_get_priority (NMDevice *self) return 350; case NM_DEVICE_TYPE_VLAN: return 400; + case NM_DEVICE_TYPE_BRIDGE: + return 425; case NM_DEVICE_TYPE_MODEM: return 450; case NM_DEVICE_TYPE_BT: @@ -700,23 +712,37 @@ nm_device_get_priority (NMDevice *self) return 600; case NM_DEVICE_TYPE_OLPC_MESH: return 650; - default: + case NM_DEVICE_TYPE_GENERIC: return 950; + case NM_DEVICE_TYPE_UNKNOWN: + return 10000; + case NM_DEVICE_TYPE_UNUSED1: + case NM_DEVICE_TYPE_UNUSED2: + /* omit default: to get compiler warning about missing switch cases */ + break; } + return 11000; } guint32 nm_device_get_ip4_route_metric (NMDevice *self) { NMConnection *connection; + NMSettingIPConfig *s_ip = NULL; gint64 route_metric = -1; g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); connection = nm_device_get_connection (self); - if (connection) - route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip4_config (connection)); + s_ip = nm_connection_get_setting_ip4_config (connection); + + /* Slave interfaces don't have IP settings, but we may get here when + * external changes are made or when noticing IP changes when starting + * the slave connection. + */ + if (s_ip) + route_metric = nm_setting_ip_config_get_route_metric (s_ip); return route_metric >= 0 ? route_metric : nm_device_get_priority (self); } @@ -725,14 +751,21 @@ guint32 nm_device_get_ip6_route_metric (NMDevice *self) { NMConnection *connection; + NMSettingIPConfig *s_ip = NULL; gint64 route_metric = -1; g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); connection = nm_device_get_connection (self); - if (connection) - route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip6_config (connection)); + s_ip = nm_connection_get_setting_ip6_config (connection); + + /* Slave interfaces don't have IP settings, but we may get here when + * external changes are made or when noticing IP changes when starting + * the slave connection. + */ + if (s_ip) + route_metric = nm_setting_ip_config_get_route_metric (s_ip); return route_metric >= 0 ? route_metric : nm_device_get_priority (self); } @@ -1128,6 +1161,7 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) g_source_remove (priv->carrier_wait_id); priv->carrier_wait_id = 0; nm_device_remove_pending_action (self, "carrier wait", TRUE); + _carrier_wait_check_queued_act_request (self); } } else if (state <= NM_DEVICE_STATE_DISCONNECTED) { _LOGI (LOGD_DEVICE, "link disconnected"); @@ -1717,16 +1751,24 @@ nm_device_removed (NMDevice *self) static gboolean -is_available (NMDevice *self) +is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - return priv->carrier || priv->ignore_carrier; + if (priv->carrier || priv->ignore_carrier) + return TRUE; + + if (NM_FLAGS_HAS (flags, NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER)) + return TRUE; + + return FALSE; } /** * nm_device_is_available: * @self: the #NMDevice + * @flags: additional flags to influence the check. Flags have the + * meaning to increase the availability of a device. * * Checks if @self would currently be capable of activating a * connection. In particular, it checks that the device is ready (eg, @@ -1742,14 +1784,14 @@ is_available (NMDevice *self) * Returns: %TRUE or %FALSE */ gboolean -nm_device_is_available (NMDevice *self) +nm_device_is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); if (priv->firmware_missing) return FALSE; - return NM_DEVICE_GET_CLASS (self)->is_available (self); + return NM_DEVICE_GET_CLASS (self)->is_available (self, flags); } gboolean @@ -1873,7 +1915,7 @@ can_auto_connect (NMDevice *self, if (!nm_setting_connection_get_autoconnect (s_con)) return FALSE; - return nm_device_connection_is_available (self, connection, FALSE); + return nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL); } /** @@ -3760,7 +3802,7 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason) } /* success; already have the LL address; kick off DHCP */ - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS || ret == NM_ACT_STAGE_RETURN_FINISH); } if (!dhcp6_start_with_link_ready (self, connection)) { @@ -3925,7 +3967,7 @@ linklocal6_start (NMDevice *self) linklocal6_cleanup (self); if (have_ip6_address (priv->ip6_config, TRUE)) - return NM_ACT_STAGE_RETURN_SUCCESS; + return NM_ACT_STAGE_RETURN_FINISH; connection = nm_device_get_connection (self); g_assert (connection); @@ -4126,14 +4168,8 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) } } - /* hop_limit == 0 is a special value "unspecified", so do not touch - * in this case */ - if (changed & NM_RDISC_CONFIG_HOP_LIMIT && rdisc->hop_limit > 0) { - char val[16]; - - g_snprintf (val, sizeof (val), "%d", rdisc->hop_limit); - nm_device_ipv6_sysctl_set (self, "hop_limit", val); - } + if (changed & NM_RDISC_CONFIG_HOP_LIMIT) + nm_platform_sysctl_set_ip6_hop_limit_safe (nm_device_get_ip_iface (self), rdisc->hop_limit); if (changed & NM_RDISC_CONFIG_MTU) { char val[16]; @@ -4241,7 +4277,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) } /* success; already have the LL address; kick off router discovery */ - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS || ret == NM_ACT_STAGE_RETURN_FINISH); return addrconf6_start_with_link_ready (self); } @@ -4345,11 +4381,12 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) if (enable) { /* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */ value = nm_platform_sysctl_get (nm_utils_ip6_property_path (iface, "disable_ipv6")); - if (g_strcmp0 (value, "0") == 0) { + if (g_strcmp0 (value, "0") == 0) nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); - nm_device_ipv6_sysctl_set (self, "disable_ipv6", "0"); - } g_free (value); + + /* Ensure IPv6 is enabled */ + nm_device_ipv6_sysctl_set (self, "disable_ipv6", "0"); } } @@ -4445,7 +4482,7 @@ act_stage3_ip6_config_start (NMDevice *self, connection = nm_device_get_connection (self); g_assert (connection); - if ( connection_ip4_method_requires_carrier (connection, NULL) + if ( connection_ip6_method_requires_carrier (connection, NULL) && priv->is_master && !priv->carrier) { _LOGI (LOGD_IP6 | LOGD_DEVICE, @@ -4519,7 +4556,7 @@ act_stage3_ip6_config_start (NMDevice *self, ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) { ret = linklocal6_start (self); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { + if (ret == NM_ACT_STAGE_RETURN_FINISH) { /* New blank config; LL address is already in priv->ext_ip6_config */ *out_config = nm_ip6_config_new (); g_assert (*out_config); @@ -4626,8 +4663,13 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); return FALSE; } else if (ret == NM_ACT_STAGE_RETURN_STOP) { - /* Early finish */ + /* Activation not wanted */ priv->ip6_state = IP_FAIL; + } else if (ret == NM_ACT_STAGE_RETURN_FINISH) { + /* Early finish, nothing more to do */ + priv->ip6_state = IP_DONE; + if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG) + nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); } else if (ret == NM_ACT_STAGE_RETURN_WAIT) { /* Wait for something to try IP config again */ priv->ip6_state = IP_WAIT; @@ -5569,6 +5611,15 @@ disconnect_cb (NMDevice *self, } static void +_clear_queued_act_request (NMDevicePrivate *priv) +{ + if (priv->queued_act_request) { + nm_active_connection_set_state ((NMActiveConnection *) priv->queued_act_request, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); + g_clear_object (&priv->queued_act_request); + } +} + +static void impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context) { NMConnection *connection; @@ -5670,26 +5721,97 @@ _device_activate (NMDevice *self, NMActRequest *req) nm_device_activate_schedule_stage1_device_prepare (self); } +static void +_carrier_wait_check_queued_act_request (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMActRequest *queued_req; + + if ( !priv->queued_act_request + || !priv->queued_act_request_is_waiting_for_carrier) + return; + + priv->queued_act_request_is_waiting_for_carrier = FALSE; + if (!priv->carrier) { + _LOGD (LOGD_DEVICE, "Cancel queued activation request as we have no carrier after timeout"); + g_clear_object (&priv->queued_act_request); + } else { + _LOGD (LOGD_DEVICE, "Activate queued activation request as we now have carrier"); + queued_req = priv->queued_act_request; + priv->queued_act_request = NULL; + _device_activate (self, queued_req); + g_object_unref (queued_req); + } +} + +static gboolean +_carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *connection; + + /* If we have carrier or if we are not waiting for it, the activation + * request is not blocked waiting for carrier. */ + if (priv->carrier) + return FALSE; + if (priv->carrier_wait_id == 0) + return FALSE; + + connection = nm_act_request_get_connection (req); + + if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL, NULL)) { + /* We passed all @flags we have, and no @specific_object. + * This equals maximal availability, if a connection is not available + * in this case, it is not waiting for carrier. + * + * Actually, why are we even trying to activate it? Strange, but whatever + * the reason, don't wait for carrier. + */ + return FALSE; + } + + if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, NULL)) { + /* The connection was available with flags ALL, and it is still available + * if we pretend not to wait for carrier. That means that the + * connection is available now, and does not wait for carrier. + * + * Since the flags increase the availability of a connection, when checking + * ALL&~WAITING_CARRIER, it means that we certainly would wait for carrier. */ + return FALSE; + } + + /* The activation request must wait for carrier. */ + return TRUE; +} + void nm_device_queue_activation (NMDevice *self, NMActRequest *req) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean must_queue; + + must_queue = _carrier_wait_check_act_request_must_queue (self, req); - if (!priv->act_request) { + if (!priv->act_request && !must_queue) { /* Just activate immediately */ _device_activate (self, req); return; } /* supercede any already-queued request */ - g_clear_object (&priv->queued_act_request); + _clear_queued_act_request (priv); priv->queued_act_request = g_object_ref (req); + priv->queued_act_request_is_waiting_for_carrier = must_queue; - /* Deactivate existing activation request first */ - _LOGI (LOGD_DEVICE, "disconnecting for new activation request."); - nm_device_state_changed (self, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_NONE); + _LOGD (LOGD_DEVICE, "queue activation request waiting for %s", must_queue ? "carrier" : "currently active connection to disconnect"); + + if (priv->act_request) { + /* Deactivate existing activation request first */ + _LOGI (LOGD_DEVICE, "disconnecting for new activation request."); + nm_device_state_changed (self, + NM_DEVICE_STATE_DEACTIVATING, + NM_DEVICE_STATE_REASON_NEW_ACTIVATION); + } } /* @@ -5915,7 +6037,7 @@ nm_device_set_ip6_config (NMDevice *self, nm_ip6_config_export (new_config); } - _LOGD (LOGD_IP4, "set IP6Config instance (%s)", + _LOGD (LOGD_IP6, "set IP6Config instance (%s)", nm_ip6_config_get_dbus_path (new_config)); } } else if (old_config) { @@ -6231,6 +6353,9 @@ carrier_wait_timeout (gpointer user_data) NM_DEVICE_GET_PRIVATE (self)->carrier_wait_id = 0; nm_device_remove_pending_action (self, "carrier wait", TRUE); + + _carrier_wait_check_queued_act_request (self); + return G_SOURCE_REMOVE; } @@ -6295,12 +6420,11 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) * a timeout is reached. */ if (device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { - if (priv->carrier_wait_id) { + if (priv->carrier_wait_id) g_source_remove (priv->carrier_wait_id); - nm_device_remove_pending_action (self, "carrier wait", TRUE); - } + else + nm_device_add_pending_action (self, "carrier wait", TRUE); priv->carrier_wait_id = g_timeout_add_seconds (5, carrier_wait_timeout, self); - nm_device_add_pending_action (self, "carrier wait", TRUE); } /* Can only get HW address of some devices when they are up */ @@ -6728,12 +6852,12 @@ nm_device_set_unmanaged_quitting (NMDevice *self) /* It's OK to block here because we're quitting */ if (nm_device_is_activating (self) || priv->state == NM_DEVICE_STATE_ACTIVATED) - _set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_REMOVED, TRUE); + _set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_NOW_UNMANAGED, TRUE); nm_device_set_unmanaged (self, NM_UNMANAGED_INTERNAL, TRUE, - NM_DEVICE_STATE_REASON_REMOVED); + NM_DEVICE_STATE_REASON_NOW_UNMANAGED); } /** @@ -6788,48 +6912,45 @@ nm_device_set_dhcp_anycast_address (NMDevice *self, const char *addr) } /** - * nm_device_connection_is_available(): + * nm_device_check_connection_available(): * @self: the #NMDevice * @connection: the #NMConnection to check for availability - * @allow_device_override: set to %TRUE to let the device do specific checks + * @flags: flags to affect the decision making of whether a connection + * is available. Adding a flag can only make a connection more available, + * not less. + * @specific_object: a device type dependent argument to further + * filter the result. Passing a non %NULL specific object can only reduce + * the availability of a connection. * - * Check if @connection is available to be activated on @self. Normally this - * only checks if the connection is in @self's AvailableConnections property. - * If @allow_device_override is %TRUE then the device is asked to do specific - * checks that may bypass the AvailableConnections property. + * Check if @connection is available to be activated on @self. * * Returns: %TRUE if @connection can be activated on @self */ gboolean -nm_device_connection_is_available (NMDevice *self, - NMConnection *connection, - gboolean allow_device_override) +nm_device_check_connection_available (NMDevice *self, + NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, + const char *specific_object) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean available = FALSE; + NMDeviceState state; - if (nm_device_get_default_unmanaged (self) && (priv->state == NM_DEVICE_STATE_UNMANAGED)) { - /* default-unmanaged devices in UNMANAGED state have no available connections - * so we must manually check whether the connection is available here. - */ - if ( nm_device_check_connection_compatible (self, connection) - && NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, NULL)) - return TRUE; - } + state = nm_device_get_state (self); + if (state < NM_DEVICE_STATE_UNMANAGED) + return FALSE; + if ( state < NM_DEVICE_STATE_UNAVAILABLE + && nm_device_get_unmanaged_flag (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT)) + return FALSE; + if ( state < NM_DEVICE_STATE_DISCONNECTED + && ( ( !NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) + && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) + || ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) + && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER)))) + return FALSE; - available = !!g_hash_table_lookup (priv->available_connections, connection); - if (!available && allow_device_override) { - /* FIXME: hack for hidden WiFi becuase clients didn't consistently - * set the 'hidden' property to indicate hidden SSID networks. If - * activating but the network isn't available let the device recheck - * availability. - */ - if ( nm_device_check_connection_compatible (self, connection) - && NM_DEVICE_GET_CLASS (self)->check_connection_available_wifi_hidden) - available = NM_DEVICE_GET_CLASS (self)->check_connection_available_wifi_hidden (self, connection); - } + if (!nm_device_check_connection_compatible (self, connection)) + return FALSE; - return available; + return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object); } static void @@ -6849,17 +6970,10 @@ _clear_available_connections (NMDevice *self, gboolean do_signal) static gboolean _try_add_available_connection (NMDevice *self, NMConnection *connection) { - if ( nm_device_get_state (self) < NM_DEVICE_STATE_DISCONNECTED - && !nm_device_get_default_unmanaged (self)) - return FALSE; - - if (nm_device_check_connection_compatible (self, connection)) { - if (NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, NULL)) { - g_hash_table_insert (NM_DEVICE_GET_PRIVATE (self)->available_connections, - g_object_ref (connection), - GUINT_TO_POINTER (1)); - return TRUE; - } + if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL)) { + g_hash_table_add (NM_DEVICE_GET_PRIVATE (self)->available_connections, + g_object_ref (connection)); + return TRUE; } return FALSE; } @@ -6873,15 +6987,28 @@ _del_available_connection (NMDevice *self, NMConnection *connection) static gboolean check_connection_available (NMDevice *self, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + /* Connections which require a network connection are not available when * the device has no carrier, even with ignore-carrer=TRUE. */ - if (NM_DEVICE_GET_PRIVATE (self)->carrier == FALSE) - return connection_requires_carrier (connection) ? FALSE : TRUE; + if ( priv->carrier + || !connection_requires_carrier (connection)) + return TRUE; - return TRUE; + if ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) + && priv->carrier_wait_id != 0) { + /* The device has no carrier though the connection requires it. + * + * If we are still waiting for carrier, the connection is available + * for an explicit user-request. */ + return TRUE; + } + + return FALSE; } void @@ -6933,8 +7060,8 @@ nm_device_get_available_connections (NMDevice *self, const char *specific_object /* If a specific object is given, only include connections that are * compatible with it. */ - if ( !specific_object - || NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, specific_object)) + if ( !specific_object /* << Optimization: we know that the connection is available without @specific_object. */ + || nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, specific_object)) g_ptr_array_add (array, connection); } } @@ -7190,7 +7317,7 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure) * */ static void -nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason) +nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, gboolean deconfigure) { NMDevicePrivate *priv; int ifindex; @@ -7205,12 +7332,14 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason) /* Save whether or not we tried IPv6 for later */ priv = NM_DEVICE_GET_PRIVATE (self); - _cleanup_generic_pre (self, TRUE); + _cleanup_generic_pre (self, deconfigure); /* Turn off kernel IPv6 */ - set_disable_ipv6 (self, "1"); - nm_device_ipv6_sysctl_set (self, "accept_ra", "0"); - nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0"); + if (deconfigure) { + set_disable_ipv6 (self, "1"); + nm_device_ipv6_sysctl_set (self, "accept_ra", "0"); + nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0"); + } /* Call device type-specific deactivation */ if (NM_DEVICE_GET_CLASS (self)->deactivate) @@ -7231,7 +7360,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason) nm_platform_address_flush (ifindex); } - _cleanup_generic_post (self, TRUE); + _cleanup_generic_post (self, deconfigure); } static char * @@ -7332,7 +7461,7 @@ nm_device_spawn_iface_helper (NMDevice *self) } hostname = nm_dhcp_client_get_hostname (priv->dhcp4_client); - if (client_id) { + if (hostname) { g_ptr_array_add (argv, g_strdup ("--dhcp4-hostname")); g_ptr_array_add (argv, g_strdup (hostname)); } @@ -7430,6 +7559,69 @@ ip6_managed_setup (NMDevice *self) } static void +deactivate_async_ready (NMDevice *self, + GAsyncResult *res, + gpointer user_data) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceStateReason reason = GPOINTER_TO_UINT (user_data); + GError *error = NULL; + + NM_DEVICE_GET_CLASS (self)->deactivate_async_finish (self, res, &error); + + /* If operation cancelled, just return */ + if ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) + || (priv->deactivating_cancellable && g_cancellable_is_cancelled (priv->deactivating_cancellable))) { + nm_log_warn (LOGD_DEVICE, "Deactivation (%s) cancelled", + nm_device_get_iface (self)); + } + /* In every other case, transition to the DISCONNECTED state */ + else { + if (error) + nm_log_warn (LOGD_DEVICE, "Deactivation (%s) failed: %s", + nm_device_get_iface (self), + error->message); + nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); + } + + g_clear_object (&priv->deactivating_cancellable); + g_clear_error (&error); +} + +static void +deactivate_dispatcher_complete (guint call_id, gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceStateReason reason; + + g_return_if_fail (call_id == priv->dispatcher.call_id); + g_return_if_fail (priv->dispatcher.post_state == NM_DEVICE_STATE_DISCONNECTED); + + reason = priv->dispatcher.post_state_reason; + + priv->dispatcher.call_id = 0; + priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; + priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; + + if (priv->deactivating_cancellable) { + g_warn_if_reached (); + g_cancellable_cancel (priv->deactivating_cancellable); + g_clear_object (&priv->deactivating_cancellable); + } + + if ( NM_DEVICE_GET_CLASS (self)->deactivate_async + && NM_DEVICE_GET_CLASS (self)->deactivate_async_finish) { + priv->deactivating_cancellable = g_cancellable_new (); + NM_DEVICE_GET_CLASS (self)->deactivate_async (self, + priv->deactivating_cancellable, + (GAsyncReadyCallback) deactivate_async_ready, + GUINT_TO_POINTER (reason)); + } else + nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); +} + +static void _set_state_full (NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, @@ -7473,13 +7665,15 @@ _set_state_full (NMDevice *self, nm_device_queued_state_clear (self); dispatcher_cleanup (self); + if (priv->deactivating_cancellable) + g_cancellable_cancel (priv->deactivating_cancellable); /* Cache the activation request for the dispatcher */ req = priv->act_request ? g_object_ref (priv->act_request) : NULL; if (state <= NM_DEVICE_STATE_UNAVAILABLE) { _clear_available_connections (self, TRUE); - g_clear_object (&priv->queued_act_request); + _clear_queued_act_request (priv); } /* Update the available connections list when a device first becomes available */ @@ -7494,12 +7688,16 @@ _set_state_full (NMDevice *self, case NM_DEVICE_STATE_UNMANAGED: nm_device_set_firmware_missing (self, FALSE); if (old_state > NM_DEVICE_STATE_UNMANAGED) { - /* Clean up if the device is now unmanaged but was activated */ - if (nm_device_get_act_request (self)) - nm_device_cleanup (self, reason); - nm_device_take_down (self, TRUE); - set_nm_ipv6ll (self, FALSE); - restore_ip6_properties (self); + if (reason == NM_DEVICE_STATE_REASON_REMOVED) { + nm_device_cleanup (self, reason, FALSE); + } else { + /* Clean up if the device is now unmanaged but was activated */ + if (nm_device_get_act_request (self)) + nm_device_cleanup (self, reason, TRUE); + nm_device_take_down (self, TRUE); + set_nm_ipv6ll (self, FALSE); + restore_ip6_properties (self); + } } break; case NM_DEVICE_STATE_UNAVAILABLE: @@ -7524,7 +7722,7 @@ _set_state_full (NMDevice *self, * Note that we "deactivate" the device even when coming from * UNMANAGED, to ensure that it's in a clean state. */ - nm_device_cleanup (self, reason); + nm_device_cleanup (self, reason, TRUE); } break; case NM_DEVICE_STATE_DISCONNECTED: @@ -7534,7 +7732,7 @@ _set_state_full (NMDevice *self, */ set_nm_ipv6ll (self, TRUE); - nm_device_cleanup (self, reason); + nm_device_cleanup (self, reason, TRUE); } else if (old_state < NM_DEVICE_STATE_DISCONNECTED) { if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) { /* Ensure IPv6 is set up as it may not have been done when @@ -7575,7 +7773,7 @@ _set_state_full (NMDevice *self, * we can't change states again from the state handler for a variety of * reasons. */ - if (nm_device_is_available (self)) { + if (nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { _LOGD (LOGD_DEVICE, "device is available, will transition to DISCONNECTED"); nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); } else { @@ -7597,16 +7795,17 @@ _set_state_full (NMDevice *self, if (!nm_dispatcher_call (DISPATCHER_ACTION_PRE_DOWN, nm_act_request_get_connection (req), self, - dispatcher_complete_proceed_state, + deactivate_dispatcher_complete, self, &priv->dispatcher.call_id)) { /* Just proceed on errors */ - dispatcher_complete_proceed_state (0, self); + deactivate_dispatcher_complete (0, self); } } break; case NM_DEVICE_STATE_DISCONNECTED: - if (priv->queued_act_request) { + if ( priv->queued_act_request + && !priv->queued_act_request_is_waiting_for_carrier) { NMActRequest *queued_req; queued_req = priv->queued_act_request; @@ -8057,6 +8256,9 @@ constructor (GType type, g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ip_changed), self); g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self); + /* trigger initial ip config change to initialize ip-config */ + priv->queued_ip_config_id = g_idle_add (queued_ip_config_change, self); + if (nm_platform_check_support_user_ipv6ll ()) { int ip_ifindex = nm_device_get_ip_ifindex (self); @@ -8103,6 +8305,7 @@ constructed (GObject *object) if (priv->ifindex > 0) { priv->is_software = nm_platform_link_is_software (priv->ifindex); priv->physical_port_id = nm_platform_link_get_physical_port_id (priv->ifindex); + priv->dev_id = nm_platform_link_get_dev_id (priv->ifindex); priv->mtu = nm_platform_link_get_mtu (priv->ifindex); } /* Indicate software device in capabilities. */ @@ -8164,7 +8367,7 @@ dispose (GObject *object) _cleanup_generic_post (self, FALSE); - g_clear_pointer (&priv->ip6_saved_properties, g_hash_table_unref); + g_hash_table_remove_all (priv->ip6_saved_properties); if (priv->recheck_assume_id) { g_source_remove (priv->recheck_assume_id); @@ -8180,15 +8383,14 @@ dispose (GObject *object) priv->con_provider = NULL; } - g_hash_table_unref (priv->available_connections); - priv->available_connections = NULL; + g_hash_table_remove_all (priv->available_connections); if (priv->carrier_wait_id) { g_source_remove (priv->carrier_wait_id); priv->carrier_wait_id = 0; } - g_clear_object (&priv->queued_act_request); + _clear_queued_act_request (priv); platform = nm_platform_get (); g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ip_changed), self); @@ -8218,6 +8420,9 @@ finalize (GObject *object) g_free (priv->type_desc); g_free (priv->dhcp_anycast_address); + g_hash_table_unref (priv->ip6_saved_properties); + g_hash_table_unref (priv->available_connections); + G_OBJECT_CLASS (nm_device_parent_class)->finalize (object); } diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index b3855c74..e204af84 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -23,6 +23,7 @@ #define __NETWORKMANAGER_DEVICE_H__ #include <glib-object.h> +#include <gio/gio.h> #include <dbus/dbus-glib.h> #include <netinet/in.h> @@ -85,10 +86,37 @@ G_BEGIN_DECLS typedef enum NMActStageReturn NMActStageReturn; +/* These flags affect whether a connection is considered available on a device + * (check_connection_available()). The flags should have the meaning of relaxing + * a condition, so that adding a flag might make a connection available that would + * not be available otherwise. Adding a flag should never make a connection + * not available if it would be available otherwise. */ +typedef enum { /*< skip >*/ + NM_DEVICE_CHECK_CON_AVAILABLE_NONE = 0, + + _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER = (1L << 0), + _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP = (1L << 1), + NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST = _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER + | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP, + + __NM_DEVICE_CHECK_CON_AVAILABLE_ALL, + NM_DEVICE_CHECK_CON_AVAILABLE_ALL = (((__NM_DEVICE_CHECK_CON_AVAILABLE_ALL - 1) << 1) - 1), +} NMDeviceCheckConAvailableFlags; + struct _NMDevice { GObject parent; }; +/* The flags have an relaxing meaning, that means, specifying more flags, can make + * a device appear more available. It can never make a device less available. */ +typedef enum { /*< skip >*/ + NM_DEVICE_CHECK_DEV_AVAILABLE_NONE = 0, + NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER = (1L << 0), + + __NM_DEVICE_CHECK_DEV_AVAILABLE_ALL, + NM_DEVICE_CHECK_DEV_AVAILABLE_ALL = (((__NM_DEVICE_CHECK_DEV_AVAILABLE_ALL - 1) << 1) - 1), +} NMDeviceCheckDevAvailableFlags; + typedef struct { GObjectClass parent; @@ -116,7 +144,7 @@ typedef struct { guint32 (* get_generic_capabilities) (NMDevice *self); - gboolean (* is_available) (NMDevice *self); + gboolean (* is_available) (NMDevice *self, NMDeviceCheckDevAvailableFlags flags); gboolean (* get_enabled) (NMDevice *self); @@ -136,19 +164,18 @@ typedef struct { * including any live network information like scan lists. The connection * is checked against the object defined by @specific_object, if given. * Returns TRUE if the connection is available; FALSE if not. + * + * The passed @flags affect whether a connection is considered + * available or not. Adding more flags, means the connection is + * *more* available. + * + * Specifying @specific_object can only reduce the availability of a connection. */ gboolean (* check_connection_available) (NMDevice *self, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object); - /* Same as check_connection_available() but called if the connection - * is not present in the activating-connections array during activation, - * to give the device a chance to allow/deny the activation. This is a - * hack only meant for hidden WiFi networks. - */ - gboolean (* check_connection_available_wifi_hidden) (NMDevice *self, - NMConnection *connection); - gboolean (* complete_connection) (NMDevice *self, NMConnection *connection, const char *specific_object, @@ -174,6 +201,16 @@ typedef struct { void (* ip4_config_pre_commit) (NMDevice *self, NMIP4Config *config); void (* ip6_config_pre_commit) (NMDevice *self, NMIP6Config *config); + /* Async deactivating (in the DEACTIVATING phase) */ + void (* deactivate_async) (NMDevice *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* deactivate_async_finish) (NMDevice *self, + GAsyncResult *res, + GError **error); + + /* Sync deactivating (in the DISCONNECTED phase) */ void (* deactivate) (NMDevice *self); gboolean (* spec_match_list) (NMDevice *self, const GSList *specs); @@ -257,7 +294,7 @@ NMConnection * nm_device_get_connection (NMDevice *dev); void nm_device_removed (NMDevice *dev); -gboolean nm_device_is_available (NMDevice *dev); +gboolean nm_device_is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags); gboolean nm_device_has_carrier (NMDevice *dev); NMConnection * nm_device_generate_connection (NMDevice *self, NMDevice *master); @@ -316,7 +353,8 @@ typedef enum { /* Boundary value */ __NM_UNMANAGED_LAST, - NM_UNMANAGED_LAST = __NM_UNMANAGED_LAST - 1, + NM_UNMANAGED_LAST = __NM_UNMANAGED_LAST - 1, + NM_UNMANAGED_ALL = ((NM_UNMANAGED_LAST << 1) - 1), } NMUnmanagedFlags; gboolean nm_device_get_managed (NMDevice *device); @@ -360,9 +398,10 @@ gboolean nm_device_has_pending_action (NMDevice *device); GPtrArray *nm_device_get_available_connections (NMDevice *device, const char *specific_object); -gboolean nm_device_connection_is_available (NMDevice *device, - NMConnection *connection, - gboolean allow_device_override); +gboolean nm_device_check_connection_available (NMDevice *device, + NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, + const char *specific_object); gboolean nm_device_notify_component_added (NMDevice *device, GObject *component); diff --git a/src/devices/team/Makefile.in b/src/devices/team/Makefile.in index 4ee30e66..29ad0598 100644 --- a/src/devices/team/Makefile.in +++ b/src/devices/team/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -81,8 +91,6 @@ host_triplet = @host@ @WITH_TEAMDCTL_TRUE@am__append_1 = ${LIBTEAMDCTL_CFLAGS} @WITH_TEAMDCTL_TRUE@am__append_2 = $(LIBTEAMDCTL_LIBS) subdir = src/devices/team -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -211,6 +220,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -237,7 +248,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -272,6 +282,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -523,7 +534,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/team/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/devices/team/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -595,14 +605,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -830,6 +840,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkglibLTLIBRARIES +.PRECIOUS: Makefile + include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 16f1fcc2..49202c36 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -41,6 +41,7 @@ #include "nm-team-enum-types.h" #include "nm-posix-signals.h" #include "nm-core-internal.h" +#include "gsystem-local-alloc.h" #include "nm-device-team-glue.h" @@ -51,8 +52,6 @@ G_DEFINE_TYPE (NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE) #define NM_DEVICE_TEAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TEAM, NMDeviceTeamPrivate)) -static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team); - typedef struct { struct teamdctl *tdc; GPid teamd_pid; @@ -68,6 +67,8 @@ enum { LAST_PROP }; +static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team); + /******************************************************************/ static guint32 @@ -77,7 +78,7 @@ get_generic_capabilities (NMDevice *device) } static gboolean -is_available (NMDevice *device) +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { if (NM_DEVICE_GET_CLASS (device)->is_up) return NM_DEVICE_GET_CLASS (device)->is_up (device); @@ -87,6 +88,7 @@ is_available (NMDevice *device) static gboolean check_connection_available (NMDevice *device, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object) { /* Connections are always available because the carrier state is determined @@ -171,6 +173,7 @@ update_connection (NMDevice *device, NMConnection *connection) { NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMSettingTeam *s_team = nm_connection_get_setting_team (connection); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); if (!s_team) { s_team = (NMSettingTeam *) nm_setting_team_new (); @@ -178,8 +181,7 @@ update_connection (NMDevice *device, NMConnection *connection) } g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_CONFIG, NULL, NULL); - teamd_start (device, s_team); - if (NM_DEVICE_TEAM_GET_PRIVATE (device)->teamd_pid > 0 && ensure_teamd_connection (device)) { + if (priv->tdc) { const char *config = NULL; int err; @@ -261,49 +263,30 @@ master_update_slave_connection (NMDevice *self, /******************************************************************/ static void -teamd_timeout_remove (NMDevice *device) +teamd_cleanup (NMDevice *device, gboolean free_tdc) { NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device); - if (priv->teamd_timeout) { - g_source_remove (priv->teamd_timeout); - priv->teamd_timeout = 0; - } -} - -static void -teamd_cleanup (NMDevice *device, gboolean device_state_failed) -{ - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device); - - if (priv->teamd_dbus_watch) { - g_bus_unwatch_name (priv->teamd_dbus_watch); - priv->teamd_dbus_watch = 0; - } - if (priv->teamd_process_watch) { g_source_remove (priv->teamd_process_watch); priv->teamd_process_watch = 0; } + if (priv->teamd_timeout) { + g_source_remove (priv->teamd_timeout); + priv->teamd_timeout = 0; + } + if (priv->teamd_pid > 0) { nm_utils_kill_child_async (priv->teamd_pid, SIGTERM, LOGD_TEAM, "teamd", 2000, NULL, NULL); priv->teamd_pid = 0; } - if (priv->tdc) { + if (priv->tdc && free_tdc) { teamdctl_disconnect (priv->tdc); teamdctl_free (priv->tdc); priv->tdc = NULL; } - - teamd_timeout_remove (device); - - if (device_state_failed) { - if (nm_device_is_activating (device) || - (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)) - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } } static gboolean @@ -314,11 +297,18 @@ teamd_timeout_cb (gpointer user_data) NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device); g_return_val_if_fail (priv->teamd_timeout, FALSE); + priv->teamd_timeout = 0; - _LOGI (LOGD_TEAM, "teamd timed out."); - teamd_cleanup (device, TRUE); + if (priv->teamd_pid && !priv->tdc) { + /* Timed out launching our own teamd process */ + _LOGW (LOGD_TEAM, "teamd timed out."); + teamd_cleanup (device, TRUE); - return FALSE; + g_warn_if_fail (nm_device_is_activating (device)); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } + + return G_SOURCE_REMOVE; } static void @@ -335,43 +325,77 @@ teamd_dbus_appeared (GDBusConnection *connection, g_return_if_fail (priv->teamd_dbus_watch); _LOGI (LOGD_TEAM, "teamd appeared on D-Bus"); - teamd_timeout_remove (device); + nm_device_queue_recheck_assume (device); + + /* If another teamd grabbed the bus name while our teamd was starting, + * just ignore the death of our teamd and run with the existing one. + */ + if (priv->teamd_process_watch) { + gs_unref_variant GVariant *ret = NULL; + guint32 pid; + + ret = g_dbus_connection_call_sync (connection, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionUnixProcessID", + g_variant_new ("(s)", name_owner), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 2000, + NULL, + NULL); + g_variant_get (ret, "(u)", &pid); + + if (pid != priv->teamd_pid) + teamd_cleanup (device, FALSE); + } + /* Grab a teamd control handle even if we aren't going to use it + * immediately. But if we are, and grabbing it failed, fail the + * device activation. + */ success = ensure_teamd_connection (device); if (nm_device_get_state (device) == NM_DEVICE_STATE_PREPARE) { if (success) nm_device_activate_schedule_stage2_device_config (device); else if (!nm_device_uses_assumed_connection (device)) nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - return; } } static void -teamd_dbus_vanished (GDBusConnection *connection, +teamd_dbus_vanished (GDBusConnection *dbus_connection, const gchar *name, gpointer user_data) { NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); + NMDeviceState state = nm_device_get_state (device); g_return_if_fail (priv->teamd_dbus_watch); - if (priv->teamd_timeout) { + if (!priv->tdc) { /* g_bus_watch_name will always raise an initial signal, to indicate whether the - * name exists/not exists initially. Do not take this as a failure, until the - * startup timeout is over. - * - * Note that g_bus_watch_name is guaranteed to alternate vanished/appeared signals, - * so we won't hit this condition again (because the next signal is either 'appeared' - * or 'timeout'). */ - _LOGD (LOGD_TEAM, "teamd vanished from D-Bus (ignored)"); + * name exists/not exists initially. Do not take this as a failure if it hadn't + * previously appeared. + */ + _LOGD (LOGD_TEAM, "teamd not on D-Bus (ignored)"); return; } _LOGI (LOGD_TEAM, "teamd vanished from D-Bus"); teamd_cleanup (device, TRUE); + + /* Attempt to respawn teamd */ + if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_ACTIVATED) { + NMConnection *connection = nm_device_get_connection (device); + + g_assert (connection); + if (!teamd_start (device, nm_connection_get_setting_team (connection))) + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } } static void @@ -380,13 +404,24 @@ teamd_process_watch_cb (GPid pid, gint status, gpointer user_data) NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); + NMDeviceState state = nm_device_get_state (device); g_return_if_fail (priv->teamd_process_watch); - _LOGI (LOGD_TEAM, "teamd died with status %d", status); - priv->teamd_process_watch = 0; + _LOGD (LOGD_TEAM, "teamd died with status %d", status); priv->teamd_pid = 0; - teamd_cleanup (device, TRUE); + priv->teamd_process_watch = 0; + + /* If teamd quit within 5 seconds of starting, it's probably hosed + * and will just die again, so fail the activation. + */ + if (priv->teamd_timeout && + (state >= NM_DEVICE_STATE_PREPARE) && + (state <= NM_DEVICE_STATE_ACTIVATED)) { + _LOGW (LOGD_TEAM, "teamd process quit unexpectedly; failing activation"); + teamd_cleanup (device, TRUE); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } } static void @@ -407,28 +442,41 @@ teamd_child_setup (gpointer user_data G_GNUC_UNUSED) } static gboolean +teamd_kill (NMDeviceTeam *self, const char *teamd_binary, GError **error) +{ + gs_unref_ptrarray GPtrArray *argv = NULL; + gs_free char *tmp_str = NULL; + + if (!teamd_binary) { + teamd_binary = nm_utils_find_helper ("teamd", NULL, NULL); + if (!teamd_binary) { + _LOGW (LOGD_TEAM, "Activation: (team) failed to start teamd: teamd binary not found"); + return FALSE; + } + } + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (gpointer) teamd_binary); + g_ptr_array_add (argv, (gpointer) "-k"); + g_ptr_array_add (argv, (gpointer) "-t"); + g_ptr_array_add (argv, (gpointer) nm_device_get_iface (NM_DEVICE (self))); + g_ptr_array_add (argv, NULL); + + _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); + return g_spawn_sync ("/", (char **) argv->pdata, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, NULL, error); +} + +static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team) { NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); const char *iface = nm_device_get_ip_iface (device); - char *tmp_str = NULL; - const char *config; + gs_unref_ptrarray GPtrArray *argv = NULL; + gs_free_error GError *error = NULL; + gs_free char *tmp_str = NULL; const char *teamd_binary; - GPtrArray *argv; - GError *error = NULL; - gboolean ret; - int status; - - if (priv->teamd_dbus_watch || - priv->teamd_process_watch || - priv->teamd_pid > 0 || - priv->tdc || - priv->teamd_timeout) - { - /* Just return if teamd_start() was already called */ - return TRUE; - } + const char *config; teamd_binary = nm_utils_find_helper ("teamd", NULL, NULL); if (!teamd_binary) { @@ -436,20 +484,12 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team) return FALSE; } - /* Kill teamd for same named device first if it is there */ - argv = g_ptr_array_new (); - g_ptr_array_add (argv, (gpointer) teamd_binary); - g_ptr_array_add (argv, (gpointer) "-k"); - g_ptr_array_add (argv, (gpointer) "-t"); - g_ptr_array_add (argv, (gpointer) iface); - g_ptr_array_add (argv, NULL); - - _LOGD (LOGD_TEAM, "running: %s", - (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); - g_clear_pointer (&tmp_str, g_free); - - ret = g_spawn_sync ("/", (char **) argv->pdata, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, &status, &error); - g_ptr_array_free (argv, TRUE); + if (priv->teamd_process_watch || priv->teamd_pid > 0 || priv->tdc) { + g_warn_if_reached (); + if (!priv->teamd_pid) + teamd_kill (self, teamd_binary, NULL); + teamd_cleanup (device, TRUE); + } /* Start teamd now */ argv = g_ptr_array_new (); @@ -472,83 +512,90 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team) g_ptr_array_add (argv, (gpointer) "-gg"); g_ptr_array_add (argv, NULL); - _LOGD (LOGD_TEAM, "running: %s", - (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); - g_clear_pointer (&tmp_str, g_free); - - /* Start a timeout for teamd to appear at D-Bus */ - priv->teamd_timeout = g_timeout_add_seconds (5, teamd_timeout_cb, device); - - /* Register D-Bus name watcher */ - tmp_str = g_strdup_printf ("org.libteam.teamd.%s", iface); - priv->teamd_dbus_watch = g_bus_watch_name (G_BUS_TYPE_SYSTEM, - tmp_str, - G_BUS_NAME_WATCHER_FLAGS_NONE, - teamd_dbus_appeared, - teamd_dbus_vanished, - device, - NULL); - g_free (tmp_str); - - ret = g_spawn_async ("/", (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, - &teamd_child_setup, NULL, &priv->teamd_pid, &error); - g_ptr_array_free (argv, TRUE); - if (!ret) { + _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); + if (!g_spawn_async ("/", (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, + teamd_child_setup, NULL, &priv->teamd_pid, &error)) { _LOGW (LOGD_TEAM, "Activation: (team) failed to start teamd: %s", error->message); - g_clear_error (&error); - teamd_cleanup (device, FALSE); + teamd_cleanup (device, TRUE); return FALSE; } + /* Start a timeout for teamd to appear at D-Bus */ + if (!priv->teamd_timeout) + priv->teamd_timeout = g_timeout_add_seconds (5, teamd_timeout_cb, device); + /* Monitor the child process so we know when it dies */ priv->teamd_process_watch = g_child_watch_add (priv->teamd_pid, teamd_process_watch_cb, device); - _LOGI (LOGD_TEAM, "Activation: (team) started teamd..."); + _LOGI (LOGD_TEAM, "Activation: (team) started teamd [pid %u]...", (guint) priv->teamd_pid); return TRUE; } -static void -teamd_stop (NMDevice *device) -{ - NMDeviceTeam *self = NM_DEVICE_TEAM (device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - - if (priv->teamd_pid > 0) - _LOGI (LOGD_TEAM, "Deactivation: stopping teamd..."); - else - _LOGD (LOGD_TEAM, "Deactivation: stopping teamd (not started)..."); - teamd_cleanup (device, FALSE); -} - static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { + NMDeviceTeam *self = NM_DEVICE_TEAM (device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + gs_free_error GError *error = NULL; NMConnection *connection; NMSettingTeam *s_team; + const char *cfg; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); ret = NM_DEVICE_CLASS (nm_device_team_parent_class)->act_stage1_prepare (device, reason); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { - connection = nm_device_get_connection (device); - g_assert (connection); - s_team = nm_connection_get_setting_team (connection); - g_assert (s_team); - if (teamd_start (device, s_team)) - ret = NM_ACT_STAGE_RETURN_POSTPONE; - else - ret = NM_ACT_STAGE_RETURN_FAILURE; + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + connection = nm_device_get_connection (device); + g_assert (connection); + s_team = nm_connection_get_setting_team (connection); + g_assert (s_team); + + if (priv->tdc) { + /* If the existing teamd config is the same as we're about to use, + * then we can proceed. If it's not the same, and we have a PID, + * kill it so we can respawn it with the right config. If we don't + * have a PID, then we must fail. + */ + cfg = teamdctl_config_get_raw (priv->tdc); + if (cfg && strcmp (cfg, nm_setting_team_get_config (s_team)) == 0) { + _LOGD (LOGD_TEAM, "using existing matching teamd config"); + return NM_ACT_STAGE_RETURN_SUCCESS; + } + + if (!priv->teamd_pid) { + _LOGD (LOGD_TEAM, "existing teamd config mismatch; killing existing via teamdctl"); + if (!teamd_kill (self, NULL, &error)) { + _LOGW (LOGD_TEAM, "existing teamd config mismatch; failed to kill existing teamd: %s", error->message); + *reason = NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED; + return NM_ACT_STAGE_RETURN_FAILURE; + } + } + + _LOGD (LOGD_TEAM, "existing teamd config mismatch; respawning..."); + teamd_cleanup (device, TRUE); } - return ret; + + return teamd_start (device, s_team) ? + NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE; } static void deactivate (NMDevice *device) { - teamd_stop (device); + NMDeviceTeam *self = NM_DEVICE_TEAM (device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); + + if (priv->teamd_pid || priv->tdc) + _LOGI (LOGD_TEAM, "deactivation: stopping teamd..."); + + if (!priv->teamd_pid) + teamd_kill (self, NULL, NULL); + teamd_cleanup (device, TRUE); } static gboolean @@ -694,6 +741,27 @@ nm_device_team_init (NMDeviceTeam * self) } static void +constructed (GObject *object) +{ + NMDevice *device = NM_DEVICE (object); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object); + char *tmp_str = NULL; + + G_OBJECT_CLASS (nm_device_team_parent_class)->constructed (object); + + /* Register D-Bus name watcher */ + tmp_str = g_strdup_printf ("org.libteam.teamd.%s", nm_device_get_ip_iface (device)); + priv->teamd_dbus_watch = g_bus_watch_name (G_BUS_TYPE_SYSTEM, + tmp_str, + G_BUS_NAME_WATCHER_FLAGS_NONE, + teamd_dbus_appeared, + teamd_dbus_vanished, + NM_DEVICE (device), + NULL); + g_free (tmp_str); +} + +static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { @@ -730,7 +798,15 @@ set_property (GObject *object, guint prop_id, static void dispose (GObject *object) { - teamd_cleanup (NM_DEVICE (object), FALSE); + NMDevice *device = NM_DEVICE (object); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object); + + if (priv->teamd_dbus_watch) { + g_bus_unwatch_name (priv->teamd_dbus_watch); + priv->teamd_dbus_watch = 0; + } + + teamd_cleanup (device, TRUE); G_OBJECT_CLASS (nm_device_team_parent_class)->dispose (object); } @@ -746,6 +822,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) parent_class->connection_type = NM_SETTING_TEAM_SETTING_NAME; /* virtual methods */ + object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; object_class->dispose = dispose; diff --git a/src/devices/wifi/Makefile.in b/src/devices/wifi/Makefile.in index 175dd900..f5e88007 100644 --- a/src/devices/wifi/Makefile.in +++ b/src/devices/wifi/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,8 +89,6 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/devices/wifi -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -226,6 +235,8 @@ am__define_uniq_tagged_files = \ ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ @@ -277,7 +288,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -312,6 +322,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -583,7 +594,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wifi/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/devices/wifi/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -658,14 +668,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -968,6 +978,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES tags tags-am uninstall uninstall-am \ uninstall-pkglibLTLIBRARIES +.PRECIOUS: Makefile + include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index 0f5aa164..dc3dfbc6 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -235,7 +235,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) } static gboolean -is_available (NMDevice *device) +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index dd7754b3..ce9a3f75 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -863,10 +863,10 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) static gboolean -_internal_check_connection_available (NMDevice *device, - NMConnection *connection, - const char *specific_object, - gboolean ignore_ap_list) +check_connection_available (NMDevice *device, + NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, + const char *specific_object) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device); NMSettingWireless *s_wifi; @@ -876,6 +876,9 @@ _internal_check_connection_available (NMDevice *device, s_wifi = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wifi, FALSE); + /* a connection that is available for a certain @specific_object, MUST + * also be available in general (without @specific_object). */ + if (specific_object) { NMAccessPoint *ap; @@ -891,8 +894,15 @@ _internal_check_connection_available (NMDevice *device, || g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0) return TRUE; - /* Hidden SSIDs obviously don't always appear in the scan list either */ - if (nm_setting_wireless_get_hidden (s_wifi) || ignore_ap_list) + /* Hidden SSIDs obviously don't always appear in the scan list either. + * + * For an explict user-activation-request, a connection is considered + * available because for hidden Wi-Fi, clients didn't consistently + * set the 'hidden' property to indicate hidden SSID networks. If + * activating but the network isn't available let the device recheck + * availability. + */ + if (nm_setting_wireless_get_hidden (s_wifi) || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) return TRUE; /* check if its visible */ @@ -904,24 +914,6 @@ _internal_check_connection_available (NMDevice *device, return FALSE; } -static gboolean -check_connection_available (NMDevice *device, - NMConnection *connection, - const char *specific_object) -{ - return _internal_check_connection_available (device, connection, specific_object, FALSE); -} - -/* FIXME: remove this function when we require the 'hidden' property to be - * set before a hidden connection can be activated. - */ -static gboolean -check_connection_available_wifi_hidden (NMDevice *device, - NMConnection *connection) -{ - return _internal_check_connection_available (device, connection, NULL, TRUE); -} - /* * List of manufacturer default SSIDs that are often unchanged by users. * @@ -1143,28 +1135,22 @@ complete_connection (NMDevice *device, } static gboolean -is_available (NMDevice *device) +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); guint32 state; - if (!priv->enabled) { - _LOGD (LOGD_WIFI, "not available because not enabled"); + if (!priv->enabled) return FALSE; - } - if (!priv->sup_iface) { - _LOGD (LOGD_WIFI, "not available because supplicant not running"); + if (!priv->sup_iface) return FALSE; - } state = nm_supplicant_interface_get_state (priv->sup_iface); if ( state < NM_SUPPLICANT_INTERFACE_STATE_READY - || state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) { - _LOGD (LOGD_WIFI, "not available because supplicant interface not ready"); + || state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) return FALSE; - } return TRUE; } @@ -1522,7 +1508,9 @@ request_wireless_scan (gpointer user_data) for (i = 0; i < ssids->len; i++) { ssid = g_ptr_array_index (ssids, i); - foo = nm_utils_ssid_to_utf8 (ssid->data, ssid->len); + foo = ssid->len > 0 + ? nm_utils_ssid_to_utf8 (ssid->data, ssid->len) + : NULL; _LOGD (LOGD_WIFI_SCAN, "(%d) probe scanning SSID '%s'", i, foo ? foo : "<hidden>"); g_free (foo); @@ -1636,6 +1624,8 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, * */ +#define WPAS_REMOVED_TAG "supplicant-removed" + static void try_fill_ssid_for_hidden_ap (NMAccessPoint *ap) { @@ -1743,6 +1733,7 @@ merge_scanned_ap (NMDeviceWifi *self, * fake, since it clearly exists somewhere. */ nm_ap_set_fake (found_ap, FALSE); + g_object_set_data (G_OBJECT (found_ap), WPAS_REMOVED_TAG, NULL); } else { /* New entry in the list */ _LOGD (LOGD_WIFI_SCAN, "adding new AP '%s' %s (%p)", @@ -1756,8 +1747,6 @@ merge_scanned_ap (NMDeviceWifi *self, } } -#define WPAS_REMOVED_TAG "supplicant-removed" - static gboolean cull_scan_list (NMDeviceWifi *self) { @@ -1912,9 +1901,23 @@ supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, g_return_if_fail (object_path != NULL); ap = get_ap_by_supplicant_path (self, object_path); - if (ap) + if (ap) { + gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 last_seen = nm_ap_get_last_seen (ap); + + /* We don't know when the supplicant last saw the AP's beacons, + * it could be two minutes or it could be 2 seconds. Because the + * supplicant doesn't send property change notifications if the + * AP's other properties don't change, our last-seen time may be + * much older the supplicant's, and the AP would be immediately + * removed from the list on the next cleanup. So update the + * last-seen time to ensure the AP sticks around for at least + * one more periodic scan. + */ + nm_ap_set_last_seen (ap, MAX (last_seen, now - SCAN_INTERVAL_MAX)); g_object_set_data (G_OBJECT (ap), WPAS_REMOVED_TAG, GUINT_TO_POINTER (TRUE)); } +} static void remove_supplicant_timeouts (NMDeviceWifi *self) @@ -2169,7 +2172,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, /* If the interface can now be activated because the supplicant is now * available, transition to DISCONNECTED. */ - if ((devstate == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device)) { + if ((devstate == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE); @@ -3335,7 +3338,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->is_available = is_available; parent_class->check_connection_compatible = check_connection_compatible; parent_class->check_connection_available = check_connection_available; - parent_class->check_connection_available_wifi_hidden = check_connection_available_wifi_hidden; parent_class->complete_connection = complete_connection; parent_class->set_enabled = set_enabled; diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index ee07cf40..66d73563 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -808,7 +808,7 @@ nm_ap_set_ssid (NMAccessPoint *ap, const guint8 *ssid, gsize len) NM80211ApFlags nm_ap_get_flags (NMAccessPoint *ap) { - g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_SEC_NONE); + g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_FLAGS_NONE); return NM_AP_GET_PRIVATE (ap)->flags; } diff --git a/src/devices/wifi/tests/Makefile.am b/src/devices/wifi/tests/Makefile.am index 09c6401f..2a7d7849 100644 --- a/src/devices/wifi/tests/Makefile.am +++ b/src/devices/wifi/tests/Makefile.am @@ -23,5 +23,6 @@ test_wifi_ap_utils_SOURCES = \ test_wifi_ap_utils_LDADD = $(top_builddir)/src/libNetworkManager.la +@VALGRIND_RULES@ TESTS = test-wifi-ap-utils diff --git a/src/devices/wifi/tests/Makefile.in b/src/devices/wifi/tests/Makefile.in index a8ae2e9d..e3b7c767 100644 --- a/src/devices/wifi/tests/Makefile.in +++ b/src/devices/wifi/tests/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -81,8 +91,6 @@ host_triplet = @host@ noinst_PROGRAMS = test-wifi-ap-utils$(EXEEXT) TESTS = test-wifi-ap-utils$(EXEEXT) subdir = src/devices/wifi/tests -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -195,6 +204,8 @@ am__tty_colors = { \ std='[m'; \ fi; \ } +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -221,7 +232,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -256,6 +266,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -494,7 +505,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wifi/tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/devices/wifi/tests/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -541,14 +551,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -888,6 +898,10 @@ uninstall-am: mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am +.PRECIOUS: Makefile + + +@VALGRIND_RULES@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/src/devices/wifi/tests/test-wifi-ap-utils.c b/src/devices/wifi/tests/test-wifi-ap-utils.c index fb335b89..3c405e26 100644 --- a/src/devices/wifi/tests/test-wifi-ap-utils.c +++ b/src/devices/wifi/tests/test-wifi-ap-utils.c @@ -785,6 +785,7 @@ test_priv_ap_leap_connection_1 (gconstpointer add_wifi) COMPARE (src, expected, success, error, 0, 0); g_object_unref (src); + g_object_unref (expected); } /*******************************************/ @@ -866,6 +867,7 @@ test_priv_ap_dynamic_wep_1 (void) COMPARE (src, expected, success, error, 0, 0); g_object_unref (src); + g_object_unref (expected); } /*******************************************/ @@ -913,6 +915,7 @@ test_priv_ap_dynamic_wep_2 (void) COMPARE (src, expected, success, error, 0, 0); g_object_unref (src); + g_object_unref (expected); } /*******************************************/ diff --git a/src/devices/wimax/Makefile.in b/src/devices/wimax/Makefile.in index f1ffb09c..32800fb7 100644 --- a/src/devices/wimax/Makefile.in +++ b/src/devices/wimax/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,8 +89,6 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/devices/wimax -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -205,6 +214,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -231,7 +242,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -266,6 +276,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -526,7 +537,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wimax/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/devices/wimax/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -600,14 +610,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -835,6 +845,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkglibLTLIBRARIES +.PRECIOUS: Makefile + nm-wimax-nsp-glue.h: $(top_srcdir)/introspection/nm-wimax-nsp.xml dbus-binding-tool --prefix=nm_wimax_nsp --mode=glib-server --output=$@ $< diff --git a/src/devices/wimax/nm-device-wimax.c b/src/devices/wimax/nm-device-wimax.c index 466cd979..0c8f1cbb 100644 --- a/src/devices/wimax/nm-device-wimax.c +++ b/src/devices/wimax/nm-device-wimax.c @@ -239,7 +239,7 @@ update_availability (NMDeviceWimax *self, gboolean old_available) NMDeviceState state; gboolean new_available, changed = FALSE; - new_available = nm_device_is_available (device); + new_available = nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); if (new_available == old_available) return FALSE; @@ -281,7 +281,7 @@ set_enabled (NMDevice *device, gboolean enabled) if (priv->enabled == enabled) return; - old_available = nm_device_is_available (NM_DEVICE (device)); + old_available = nm_device_is_available (NM_DEVICE (device), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); priv->enabled = enabled; nm_log_dbg (LOGD_WIMAX, "(%s): radio now %s", @@ -334,12 +334,16 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) static gboolean check_connection_available (NMDevice *device, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object) { NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device); const GSList *ns_iter = NULL; NMWimaxNsp *nsp; + /* a connection that is available for a certain @specific_object, MUST + * also be available in general (without @specific_object). */ + if (specific_object) { nsp = get_nsp_by_path (NM_DEVICE_WIMAX (device), specific_object); return nsp ? nm_wimax_nsp_check_compatible (nsp, connection) : FALSE; @@ -484,30 +488,21 @@ can_auto_connect (NMDevice *device, } static gboolean -is_available (NMDevice *device) +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device); - const char *iface = nm_device_get_iface (device); - if (!priv->enabled) { - nm_log_dbg (LOGD_WIMAX, "(%s): not available because not enabled", iface); + if (!priv->enabled) return FALSE; - } - if (!priv->wimaxd_enabled) { - nm_log_dbg (LOGD_WIMAX, "(%s): not available because not enabled in wimaxd", iface); + if (!priv->wimaxd_enabled) return FALSE; - } - if (!nm_wimax_util_sdk_is_initialized ()) { - nm_log_dbg (LOGD_WIMAX, "(%s): not available because WiMAX SDK not initialized", iface); + if (!nm_wimax_util_sdk_is_initialized ()) return FALSE; - } - if (!priv->sdk) { - nm_log_dbg (LOGD_WIMAX, "(%s): not available because not known to WiMAX SDK", iface); + if (!priv->sdk) return FALSE; - } return iwmxsdk_status_get (priv->sdk) >= WIMAX_API_DEVICE_STATUS_Ready; } @@ -712,7 +707,7 @@ wmx_state_change_cb (struct wmxsdk *wmxsdk, return; state = nm_device_get_state (NM_DEVICE (self)); - old_available = nm_device_is_available (NM_DEVICE (self)); + old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); priv->status = new_status; if (priv->current_nsp) @@ -1153,7 +1148,7 @@ static gboolean sdk_action_defer_cb (gpointer user_data) { NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - gboolean old_available = nm_device_is_available (NM_DEVICE (self)); + gboolean old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); NM_DEVICE_WIMAX_GET_PRIVATE (self)->sdk_action_defer_id = 0; update_availability (self, old_available); diff --git a/src/devices/wwan/Makefile.in b/src/devices/wwan/Makefile.in index 18cbfdd3..1a8aef3b 100644 --- a/src/devices/wwan/Makefile.in +++ b/src/devices/wwan/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,8 +89,6 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/devices/wwan -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -216,6 +225,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -242,7 +253,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -277,6 +287,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -553,7 +564,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wwan/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/devices/wwan/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -631,14 +641,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -866,6 +876,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkglibLTLIBRARIES +.PRECIOUS: Makefile + include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index f681e59c..f819d1d7 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -295,16 +295,19 @@ modem_state_cb (NMModem *modem, * device's enabled/disabled state. */ nm_modem_set_mm_enabled (priv->modem, priv->rf_enabled); + + /* Now allow connections without a PIN to be available */ + nm_device_recheck_available_connections (device); } - if ((dev_state >= NM_DEVICE_STATE_DISCONNECTED) && !nm_device_is_available (device)) { + if ((dev_state >= NM_DEVICE_STATE_DISCONNECTED) && !nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_MODEM_FAILED); return; } - if ((dev_state == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device)) { + if ((dev_state == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_MODEM_AVAILABLE); @@ -391,6 +394,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) static gboolean check_connection_available (NMDevice *device, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object) { NMDeviceModem *self = NM_DEVICE_MODEM (device); @@ -433,6 +437,50 @@ deactivate (NMDevice *device) nm_modem_deactivate (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device); } +/***********************************************************/ + +static gboolean +deactivate_async_finish (NMDevice *self, + GAsyncResult *res, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); +} + +static void +modem_deactivate_async_ready (NMModem *modem, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + + if (!nm_modem_deactivate_async_finish (modem, res, &error)) + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +deactivate_async (NMDevice *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + simple = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + deactivate_async); + nm_modem_deactivate_async (NM_DEVICE_MODEM_GET_PRIVATE (self)->modem, + self, + cancellable, + (GAsyncReadyCallback) modem_deactivate_async_ready, + simple); +} + +/***********************************************************/ + static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { @@ -536,24 +584,19 @@ set_enabled (NMDevice *device, gboolean enabled) } static gboolean -is_available (NMDevice *device) +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { NMDeviceModem *self = NM_DEVICE_MODEM (device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); NMModemState modem_state; - if (!priv->rf_enabled) { - _LOGD (LOGD_MB, "not available because WWAN airplane mode is on"); + if (!priv->rf_enabled) return FALSE; - } g_assert (priv->modem); modem_state = nm_modem_get_state (priv->modem); - if (modem_state <= NM_MODEM_STATE_INITIALIZING) { - _LOGD (LOGD_MB, "not available because modem is not ready (%s)", - nm_modem_state_to_string (modem_state)); + if (modem_state <= NM_MODEM_STATE_INITIALIZING) return FALSE; - } return TRUE; } @@ -638,7 +681,7 @@ set_modem (NMDeviceModem *self, NMModem *modem) static void set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) + const GValue *value, GParamSpec *pspec) { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); @@ -661,7 +704,7 @@ set_property (GObject *object, guint prop_id, static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); @@ -711,6 +754,8 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; + device_class->deactivate_async = deactivate_async; + device_class->deactivate_async_finish = deactivate_async_finish; device_class->deactivate = deactivate; device_class->act_stage1_prepare = act_stage1_prepare; device_class->act_stage2_config = act_stage2_config; diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index f8239b79..4bb72fd1 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -42,7 +42,7 @@ struct _NMModemBroadbandPrivate { MMModemSimple *simple_iface; /* Connection setup */ - MMSimpleConnectProperties *connect_properties; + MMBearer *bearer; MMBearerIpConfig *ipv4_config; MMBearerIpConfig *ipv6_config; @@ -176,78 +176,6 @@ get_bearer_ip_method (MMBearerIpConfig *config) return NM_MODEM_IP_METHOD_UNKNOWN; } -static void -connect_ready (MMModemSimple *simple_iface, - GAsyncResult *res, - NMModemBroadband *self) -{ - GError *error = NULL; - NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; - NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - - g_clear_object (&self->priv->connect_properties); - - self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error); - if (!self->priv->bearer) { - if (g_error_matches (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) || - (g_error_matches (error, - MM_CORE_ERROR, - MM_CORE_ERROR_UNAUTHORIZED) && - mm_modem_get_unlock_required (self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { - /* Request PIN */ - ask_for_pin (self); - } else { - /* Strip remote error info before logging it */ - if (g_dbus_error_is_remote_error (error)) - g_dbus_error_strip_remote_error (error); - - nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s", - nm_modem_get_uid (NM_MODEM (self)), - error && error->message ? error->message : "(unknown)"); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); - } - - g_clear_error (&error); - g_object_unref (self); - return; - } - - /* Grab IP configurations */ - self->priv->ipv4_config = mm_bearer_get_ipv4_config (self->priv->bearer); - if (self->priv->ipv4_config) - ip4_method = get_bearer_ip_method (self->priv->ipv4_config); - - self->priv->ipv6_config = mm_bearer_get_ipv6_config (self->priv->bearer); - if (self->priv->ipv6_config) - ip6_method = get_bearer_ip_method (self->priv->ipv6_config); - - if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN && - ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) { - nm_log_warn (LOGD_MB, "(%s) failed to connect modem: invalid bearer IP configuration", - nm_modem_get_uid (NM_MODEM (self))); - - error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "invalid bearer IP configuration"); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, error); - g_error_free (error); - g_object_unref (self); - return; - } - - g_object_set (self, - NM_MODEM_DATA_PORT, mm_bearer_get_interface (self->priv->bearer), - NM_MODEM_IP4_METHOD, ip4_method, - NM_MODEM_IP6_METHOD, ip6_method, - NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (self->priv->bearer), - NULL); - - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); - g_object_unref (self); -} - static MMSimpleConnectProperties * create_cdma_connect_properties (NMConnection *connection) { @@ -266,15 +194,12 @@ create_cdma_connect_properties (NMConnection *connection) } static MMSimpleConnectProperties * -create_gsm_connect_properties (NMModem *modem, - NMConnection *connection, - GError **error) +create_gsm_connect_properties (NMConnection *connection) { NMSettingGsm *setting; NMSettingPpp *s_ppp; MMSimpleConnectProperties *properties; const gchar *str; - NMModemIPType ip_type; setting = nm_connection_get_setting_gsm (connection); properties = mm_simple_connect_properties_new (); @@ -329,23 +254,137 @@ create_gsm_connect_properties (NMModem *modem, mm_simple_connect_properties_set_allowed_auth (properties, allowed_auth); } - /* Determine IP types to use when connecting */ - ip_type = nm_modem_get_connection_ip_type (modem, connection, error); - if (ip_type == NM_MODEM_IP_TYPE_UNKNOWN) { - g_object_unref (properties); - return NULL; + return properties; +} + +typedef struct { + NMModemBroadband *self; + MMModemCapability caps; + MMSimpleConnectProperties *connect_properties; + GArray *ip_types; + guint ip_types_i; + GError *first_error; +} ActStageContext; + +static void +act_stage_context_free (ActStageContext *ctx) +{ + g_clear_error (&ctx->first_error); + g_clear_pointer (&ctx->ip_types, (GDestroyNotify) g_array_unref); + g_clear_object (&ctx->connect_properties); + g_object_unref (ctx->self); + g_slice_free (ActStageContext, ctx); +} + +static void act_stage_context_step (ActStageContext *ctx); + +static void +connect_ready (MMModemSimple *simple_iface, + GAsyncResult *res, + ActStageContext *ctx) +{ + GError *error = NULL; + NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; + NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; + + ctx->self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error); + if (!ctx->self->priv->bearer) { + if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) || + (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) && + mm_modem_get_unlock_required (ctx->self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { + /* Request PIN */ + ask_for_pin (ctx->self); + g_error_free (error); + act_stage_context_free (ctx); + return; + } + + /* Save the error, if it's the first one */ + if (!ctx->first_error) { + /* Strip remote error info before saving it */ + if (g_dbus_error_is_remote_error (error)) + g_dbus_error_strip_remote_error (error); + ctx->first_error = error; + } else + g_error_free (error); + + /* If the modem/provider lies and the IP type we tried isn't supported, + * retry with the next one, if any. + */ + ctx->ip_types_i++; + act_stage_context_step (ctx); + return; } - if (ip_type == NM_MODEM_IP_TYPE_IPV4) - mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV4); - else if (ip_type == NM_MODEM_IP_TYPE_IPV6) - mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV6); - else if (ip_type == NM_MODEM_IP_TYPE_IPV4V6) - mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV4V6); - else - g_assert_not_reached (); + /* Grab IP configurations */ + ctx->self->priv->ipv4_config = mm_bearer_get_ipv4_config (ctx->self->priv->bearer); + if (ctx->self->priv->ipv4_config) + ip4_method = get_bearer_ip_method (ctx->self->priv->ipv4_config); - return properties; + ctx->self->priv->ipv6_config = mm_bearer_get_ipv6_config (ctx->self->priv->bearer); + if (ctx->self->priv->ipv6_config) + ip6_method = get_bearer_ip_method (ctx->self->priv->ipv6_config); + + if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN && + ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) { + nm_log_warn (LOGD_MB, "(%s): failed to connect modem: invalid bearer IP configuration", + nm_modem_get_uid (NM_MODEM (ctx->self))); + g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + act_stage_context_free (ctx); + return; + } + + g_object_set (ctx->self, + NM_MODEM_DATA_PORT, mm_bearer_get_interface (ctx->self->priv->bearer), + NM_MODEM_IP4_METHOD, ip4_method, + NM_MODEM_IP6_METHOD, ip6_method, + NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (ctx->self->priv->bearer), + NULL); + + g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); + act_stage_context_free (ctx); +} + +static void +act_stage_context_step (ActStageContext *ctx) +{ + if (ctx->ip_types_i < ctx->ip_types->len) { + NMModemIPType current; + + current = g_array_index (ctx->ip_types, NMModemIPType, ctx->ip_types_i); + + if (current == NM_MODEM_IP_TYPE_IPV4) + mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4); + else if (current == NM_MODEM_IP_TYPE_IPV6) + mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV6); + else if (current == NM_MODEM_IP_TYPE_IPV4V6) + mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4V6); + else + g_assert_not_reached (); + + nm_log_dbg (LOGD_MB, "(%s): launching connection with ip type '%s'", + nm_modem_get_uid (NM_MODEM (ctx->self)), + nm_modem_ip_type_to_string (current)); + + mm_modem_simple_connect (ctx->self->priv->simple_iface, + ctx->connect_properties, + NULL, + (GAsyncReadyCallback)connect_ready, + ctx); + return; + } + + /* If we have a saved error from a previous attempt, use it */ + if (!ctx->first_error) + ctx->first_error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "invalid bearer IP configuration"); + + nm_log_warn (LOGD_MB, "(%s): failed to connect modem: %s", + nm_modem_get_uid (NM_MODEM (ctx->self)), + ctx->first_error->message); + g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (ctx->first_error)); + act_stage_context_free (ctx); } static NMActStageReturn @@ -354,42 +393,55 @@ act_stage1_prepare (NMModem *_self, NMDeviceStateReason *reason) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - MMModemCapability caps; + ActStageContext *ctx; GError *error = NULL; - g_clear_object (&self->priv->connect_properties); + /* Make sure we can get the Simple interface from the modem */ + if (!self->priv->simple_iface) { + self->priv->simple_iface = mm_object_get_modem_simple (self->priv->modem_object); + if (!self->priv->simple_iface) { + nm_log_warn (LOGD_MB, "(%s) cannot access the Simple mobile broadband modem interface", + nm_modem_get_uid (NM_MODEM (self))); + *reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; + return NM_ACT_STAGE_RETURN_FAILURE; + } + } + + /* Allocate new context for this activation stage attempt */ + ctx = g_slice_new0 (ActStageContext); + ctx->self = NM_MODEM_BROADBAND (g_object_ref (self)); + ctx->caps = mm_modem_get_current_capabilities (self->priv->modem_iface); - caps = mm_modem_get_current_capabilities (self->priv->modem_iface); - if (MODEM_CAPS_3GPP (caps)) - self->priv->connect_properties = create_gsm_connect_properties (_self, connection, &error); - else if (MODEM_CAPS_3GPP2 (caps)) - self->priv->connect_properties = create_cdma_connect_properties (connection); + /* Create core connect properties based on the modem capabilities */ + if (MODEM_CAPS_3GPP (ctx->caps)) + ctx->connect_properties = create_gsm_connect_properties (connection); + else if (MODEM_CAPS_3GPP2 (ctx->caps)) + ctx->connect_properties = create_cdma_connect_properties (connection); else { - nm_log_warn (LOGD_MB, "(%s) not a mobile broadband modem", - nm_modem_get_uid (NM_MODEM (self))); + nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': not a mobile broadband modem", + nm_modem_get_uid (NM_MODEM (self)), + nm_connection_get_id (connection)); + act_stage_context_free (ctx); *reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; return NM_ACT_STAGE_RETURN_FAILURE; } + g_assert (ctx->connect_properties); - if (error) { + /* Checkout list of IP types that we need to use in the retries */ + ctx->ip_types = nm_modem_get_connection_ip_type (NM_MODEM (self), connection, &error); + if (!ctx->ip_types) { nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': %s", nm_modem_get_uid (NM_MODEM (self)), nm_connection_get_id (connection), - error->message); + error ? error->message : "unknown error"); g_clear_error (&error); + act_stage_context_free (ctx); *reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; return NM_ACT_STAGE_RETURN_FAILURE; } - if (!self->priv->simple_iface) - self->priv->simple_iface = mm_object_get_modem_simple (self->priv->modem_object); - g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (self->priv->simple_iface), MODEM_CONNECT_TIMEOUT_SECS * 1000); - mm_modem_simple_connect (self->priv->simple_iface, - self->priv->connect_properties, - NULL, - (GAsyncReadyCallback)connect_ready, - g_object_ref (self)); + act_stage_context_step (ctx); return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -566,9 +618,9 @@ set_power_state_low_ready (MMModem *modem, if (!mm_modem_set_power_state_finish (modem, result, &error)) { /* Log but ignore errors; not all modems support low power state */ - nm_log_dbg (LOGD_MB, "(%s) failed to set modem low power state: %s", - nm_modem_get_uid (NM_MODEM (self)), - error && error->message ? error->message : "(unknown)"); + nm_log_dbg (LOGD_MB, "(%s): failed to set modem low power state: %s", + nm_modem_get_uid (NM_MODEM (self)), + error && error->message ? error->message : "(unknown)"); g_clear_error (&error); } @@ -591,7 +643,7 @@ modem_disable_ready (MMModem *modem_iface, (GAsyncReadyCallback) set_power_state_low_ready, g_object_ref (self)); } else { - nm_log_warn (LOGD_MB, "(%s) failed to disable modem: %s", + nm_log_warn (LOGD_MB, "(%s): failed to disable modem: %s", nm_modem_get_uid (NM_MODEM (self)), error && error->message ? error->message : "(unknown)"); nm_modem_set_prev_state (NM_MODEM (self), "disable failed"); @@ -708,7 +760,7 @@ static_stage3_ip4_done (NMModemBroadband *self) /* DNS servers */ dns = mm_bearer_ip_config_get_dns (self->priv->ipv4_config); - for (i = 0; dns[i]; i++) { + for (i = 0; dns && dns[i]; i++) { if ( ip4_string_to_num (dns[i], &address_network) && address_network > 0) { nm_ip4_config_add_nameserver (config, address_network); @@ -761,9 +813,9 @@ stage3_ip6_done (NMModemBroadband *self) /* DHCP/SLAAC is allowed to skip addresses; other methods require it */ if (ip_method != NM_MODEM_IP_METHOD_AUTO) { error = g_error_new (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: no address given", - nm_modem_get_uid (NM_MODEM (self))); + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IPv6 configuration failed: no address given", + nm_modem_get_uid (NM_MODEM (self))); } goto out; } @@ -792,10 +844,10 @@ stage3_ip6_done (NMModemBroadband *self) if (address_string) { if (!inet_pton (AF_INET6, address_string, (void *) &(address.address))) { error = g_error_new (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", - nm_modem_get_uid (NM_MODEM (self)), - address_string); + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", + nm_modem_get_uid (NM_MODEM (self)), + address_string); goto out; } nm_log_info (LOGD_MB, " gateway %s", address_string); @@ -844,20 +896,47 @@ stage3_ip6_config_request (NMModem *_self, NMDeviceStateReason *reason) typedef struct { NMModemBroadband *self; + GSimpleAsyncResult *result; + GCancellable *cancellable; gboolean warn; -} SimpleDisconnectContext; +} DisconnectContext; static void -simple_disconnect_context_free (SimpleDisconnectContext *ctx) +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); g_object_unref (ctx->self); - g_slice_free (SimpleDisconnectContext, ctx); + 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 *res, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); } static void simple_disconnect_ready (MMModemSimple *modem_iface, GAsyncResult *res, - SimpleDisconnectContext *ctx) + DisconnectContext *ctx) { GError *error = NULL; @@ -865,33 +944,48 @@ simple_disconnect_ready (MMModemSimple *modem_iface, if (ctx->warn) nm_log_warn (LOGD_MB, "(%s) failed to disconnect modem: %s", nm_modem_get_uid (NM_MODEM (ctx->self)), - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); + error->message); + g_simple_async_result_take_error (ctx->result, error); } - simple_disconnect_context_free (ctx); + disconnect_context_complete (ctx); } static void -disconnect (NMModem *modem, - gboolean warn) +disconnect (NMModem *self, + gboolean warn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - NMModemBroadband *self = NM_MODEM_BROADBAND (modem); - SimpleDisconnectContext *ctx; - - if (!self->priv->simple_iface) - return; + DisconnectContext *ctx; - ctx = g_slice_new (SimpleDisconnectContext); + ctx = g_slice_new (DisconnectContext); ctx->self = g_object_ref (self); - + ctx->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + disconnect); /* Don't bother warning on FAILED since the modem is already gone */ ctx->warn = warn; + /* Setup cancellable */ + ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + if (disconnect_context_complete_if_cancelled (ctx)) + return; + + /* If no simple iface, we're done */ + if (!ctx->self->priv->simple_iface) { + disconnect_context_complete (ctx); + return; + } + + nm_log_dbg (LOGD_MB, "(%s): notifying ModemManager about the modem disconnection", + nm_modem_get_uid (NM_MODEM (ctx->self))); mm_modem_simple_disconnect ( ctx->self->priv->simple_iface, NULL, /* bearer path; if NULL given ALL get disconnected */ - NULL, /* cancellable */ + cancellable, (GAsyncReadyCallback)simple_disconnect_ready, ctx); } @@ -899,7 +993,7 @@ disconnect (NMModem *modem, /*****************************************************************************/ static void -deactivate (NMModem *_self, NMDevice *device) +deactivate_cleanup (NMModem *_self, NMDevice *device) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); @@ -913,7 +1007,7 @@ deactivate (NMModem *_self, NMDevice *device) self->priv->pin_tries = 0; /* Chain up parent's */ - NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate (_self, device); + NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate_cleanup (_self, device); } /*****************************************************************************/ @@ -1027,7 +1121,7 @@ get_sim_ready (MMModem *modem, NULL); g_object_unref (new_sim); } else { - nm_log_warn (LOGD_MB, "(%s) failed to retrieve SIM object: %s", + nm_log_warn (LOGD_MB, "(%s): failed to retrieve SIM object: %s", nm_modem_get_uid (NM_MODEM (self)), error && error->message ? error->message : "(unknown)"); } @@ -1062,7 +1156,7 @@ nm_modem_broadband_init (NMModemBroadband *self) static void set_property (GObject *object, guint prop_id, - const GValue *value, + const GValue *value, GParamSpec *pspec) { NMModemBroadband *self = NM_MODEM_BROADBAND (object); @@ -1095,7 +1189,7 @@ set_property (GObject *object, static void get_property (GObject *object, guint prop_id, - GValue *value, + GValue *value, GParamSpec *pspec) { NMModemBroadband *self = NM_MODEM_BROADBAND (object); @@ -1142,7 +1236,8 @@ nm_modem_broadband_class_init (NMModemBroadbandClass *klass) modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; modem_class->stage3_ip6_config_request = stage3_ip6_config_request; modem_class->disconnect = disconnect; - modem_class->deactivate = deactivate; + modem_class->disconnect_finish = disconnect_finish; + modem_class->deactivate_cleanup = deactivate_cleanup; modem_class->set_mm_enabled = set_mm_enabled; modem_class->get_user_pass = get_user_pass; modem_class->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index ba1db8a4..69eaddf3 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -175,23 +175,23 @@ 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_log_dbg (LOGD_MB, "(%s): cannot enable modem: already enabled", nm_modem_get_uid (self)); return; } if (!enabled && priv->state <= NM_MODEM_STATE_DISABLING) { - nm_log_dbg (LOGD_MB, "(%s) cannot disable modem: already disabled", + nm_log_dbg (LOGD_MB, "(%s): cannot disable modem: already disabled", nm_modem_get_uid (self)); return; } if (priv->state <= NM_MODEM_STATE_INITIALIZING) { - nm_log_dbg (LOGD_MB, "(%s) cannot enable/disable modem: initializing or failed", + nm_log_dbg (LOGD_MB, "(%s): cannot enable/disable modem: initializing or failed", nm_modem_get_uid (self)); 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_log_warn (LOGD_MB, "(%s): cannot enable/disable modem: locked", nm_modem_get_uid (self)); /* Try to unlock the modem if it's being enabled */ @@ -221,17 +221,39 @@ nm_modem_get_supported_ip_types (NMModem *self) return NM_MODEM_GET_PRIVATE (self)->ip_types; } +const gchar * +nm_modem_ip_type_to_string (NMModemIPType ip_type) +{ + switch (ip_type) { + case NM_MODEM_IP_TYPE_IPV4: + return "ipv4"; + case NM_MODEM_IP_TYPE_IPV6: + return "ipv6"; + case NM_MODEM_IP_TYPE_IPV4V6: + return "ipv4v6"; + default: + g_return_val_if_reached ("unknown"); + } +} + +static GArray * +build_single_ip_type_array (NMModemIPType type) +{ + return g_array_append_val (g_array_sized_new (FALSE, FALSE, sizeof (NMModemIPType), 1), type); +} + /** * nm_modem_get_connection_ip_type: * @self: the #NMModem * @connection: the #NMConnection to determine IP type to use * - * Given a modem and a connection, determine which NMModemIpType to use + * Given a modem and a connection, determine which #NMModemIPTypes to use * when connecting. * - * Returns: a single %NMModemIpType value + * Returns: an array of #NMModemIpType values, in the order in which they + * should be tried. */ -NMModemIPType +GArray * nm_modem_get_connection_ip_type (NMModem *self, NMConnection *connection, GError **error) @@ -265,9 +287,9 @@ nm_modem_get_connection_ip_type (NMModem *self, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection requested IPv4 but IPv4 is " "unsuported by the modem."); - return NM_MODEM_IP_TYPE_UNKNOWN; + return NULL; } - return NM_MODEM_IP_TYPE_IPV4; + return build_single_ip_type_array (NM_MODEM_IP_TYPE_IPV4); } if (ip6 && !ip4) { @@ -277,38 +299,54 @@ nm_modem_get_connection_ip_type (NMModem *self, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection requested IPv6 but IPv6 is " "unsuported by the modem."); - return NM_MODEM_IP_TYPE_UNKNOWN; + return NULL; } - return NM_MODEM_IP_TYPE_IPV6; + return build_single_ip_type_array (NM_MODEM_IP_TYPE_IPV6); } if (ip4 && ip6) { - /* Modem supports dual-stack */ - if (priv->ip_types & NM_MODEM_IP_TYPE_IPV4V6) - return NM_MODEM_IP_TYPE_IPV4V6; + NMModemIPType type; + GArray *out; - /* Both IPv4 and IPv6 requested, but modem doesn't support dual-stack; - * if one method is marked "may-fail" then use the other. - */ - if (ip6_may_fail) - return NM_MODEM_IP_TYPE_IPV4; - else if (ip4_may_fail) - return NM_MODEM_IP_TYPE_IPV6; + out = g_array_sized_new (FALSE, FALSE, sizeof (NMModemIPType), 3); + /* Modem supports dual-stack? */ + if (priv->ip_types & NM_MODEM_IP_TYPE_IPV4V6) { + type = NM_MODEM_IP_TYPE_IPV4V6; + g_array_append_val (out, type); + } + + /* If IPv6 may-fail=false, we should NOT try IPv4 as fallback */ + if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV4) && ip6_may_fail) { + type = NM_MODEM_IP_TYPE_IPV4; + g_array_append_val (out, type); + } + + /* If IPv4 may-fail=false, we should NOT try IPv6 as fallback */ + if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV6) && ip4_may_fail) { + type = NM_MODEM_IP_TYPE_IPV6; + g_array_append_val (out, type); + } + + if (out->len > 0) + return out; + + /* Error... */ + g_array_unref (out); g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection requested both IPv4 and IPv6 " "but dual-stack addressing is unsupported " "by the modem."); - return NM_MODEM_IP_TYPE_UNKNOWN; + return NULL; } g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection specified no IP configuration!"); - return NM_MODEM_IP_TYPE_UNKNOWN; + return NULL; } /*****************************************************************************/ @@ -343,9 +381,9 @@ set_data_port (NMModem *self, const char *new_data_port) static void ppp_ip4_config (NMPPPManager *ppp_manager, - const char *iface, - NMIP4Config *config, - gpointer user_data) + const char *iface, + NMIP4Config *config, + gpointer user_data) { NMModem *self = NM_MODEM (user_data); guint32 i, num; @@ -416,9 +454,9 @@ ppp_ip6_config (NMPPPManager *ppp_manager, static void ppp_stats (NMPPPManager *ppp_manager, - guint32 in_bytes, - guint32 out_bytes, - gpointer user_data) + guint32 in_bytes, + guint32 out_bytes, + gpointer user_data) { NMModem *self = NM_MODEM (user_data); NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); @@ -464,7 +502,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, "using modem-specified IP timeout: %u seconds", + nm_log_info (LOGD_PPP, "(%s): using modem-specified IP timeout: %u seconds", + nm_modem_get_uid (self), priv->mm_ip_timeout); ip_timeout = priv->mm_ip_timeout; } @@ -486,7 +525,8 @@ ppp_stage3_ip_config_start (NMModem *self, ret = NM_ACT_STAGE_RETURN_POSTPONE; } else { - nm_log_err (LOGD_PPP, "error starting PPP: (%d) %s", + nm_log_err (LOGD_PPP, "(%s): error starting PPP: (%d) %s", + nm_modem_get_uid (self), error ? error->code : -1, error && error->message ? error->message : "(unknown)"); g_error_free (error); @@ -705,7 +745,7 @@ modem_secrets_cb (NMActRequest *req, priv->secrets_id = 0; if (error) - nm_log_warn (LOGD_MB, "%s", error->message); + nm_log_warn (LOGD_MB, "(%s): %s", nm_modem_get_uid (self), error->message); g_signal_emit (self, signals[AUTH_RESULT], 0, error); } @@ -839,13 +879,12 @@ nm_modem_complete_connection (NMModem *self, /*****************************************************************************/ static void -deactivate (NMModem *self, NMDevice *device) +deactivate_cleanup (NMModem *self, NMDevice *device) { NMModemPrivate *priv; int ifindex; g_return_if_fail (NM_IS_MODEM (self)); - g_return_if_fail (NM_IS_DEVICE (device)); priv = NM_MODEM_GET_PRIVATE (self); @@ -864,15 +903,19 @@ deactivate (NMModem *self, NMDevice *device) priv->ppp_manager = NULL; } - if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC || - priv->ip4_method == NM_MODEM_IP_METHOD_AUTO || - priv->ip6_method == NM_MODEM_IP_METHOD_STATIC || - priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) { - ifindex = nm_device_get_ip_ifindex (device); - if (ifindex > 0) { - nm_platform_route_flush (ifindex); - nm_platform_address_flush (ifindex); - nm_platform_link_set_down (ifindex); + if (device) { + g_return_if_fail (NM_IS_DEVICE (device)); + + if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC || + priv->ip4_method == NM_MODEM_IP_METHOD_AUTO || + priv->ip6_method == NM_MODEM_IP_METHOD_STATIC || + priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) { + ifindex = nm_device_get_ip_ifindex (device); + if (ifindex > 0) { + nm_platform_route_flush (ifindex); + nm_platform_address_flush (ifindex); + nm_platform_link_set_down (ifindex); + } } } priv->ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; @@ -884,10 +927,176 @@ deactivate (NMModem *self, NMDevice *device) /*****************************************************************************/ +typedef enum { + DEACTIVATE_CONTEXT_STEP_FIRST, + DEACTIVATE_CONTEXT_STEP_CLEANUP, + DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP, + DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT, + DEACTIVATE_CONTEXT_STEP_LAST +} DeactivateContextStep; + +typedef struct { + NMModem *self; + NMDevice *device; + GCancellable *cancellable; + GSimpleAsyncResult *result; + DeactivateContextStep step; + NMPPPManager *ppp_manager; +} DeactivateContext; + +static void +deactivate_context_complete (DeactivateContext *ctx) +{ + if (ctx->ppp_manager) + g_object_unref (ctx->ppp_manager); + if (ctx->cancellable) + g_object_unref (ctx->cancellable); + g_simple_async_result_complete_in_idle (ctx->result); + g_object_unref (ctx->result); + g_object_unref (ctx->device); + g_object_unref (ctx->self); + g_slice_free (DeactivateContext, ctx); +} + +gboolean +nm_modem_deactivate_async_finish (NMModem *self, + GAsyncResult *res, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); +} + +static void deactivate_step (DeactivateContext *ctx); + +static void +disconnect_ready (NMModem *self, + GAsyncResult *res, + DeactivateContext *ctx) +{ + GError *error = NULL; + + if (!NM_MODEM_GET_CLASS (self)->disconnect_finish (self, res, &error)) { + g_simple_async_result_take_error (ctx->result, error); + deactivate_context_complete (ctx); + return; + } + + /* Go on */ + ctx->step++; + deactivate_step (ctx); +} + +static void +ppp_manager_stop_ready (NMPPPManager *ppp_manager, + GAsyncResult *res, + DeactivateContext *ctx) +{ + 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); + g_simple_async_result_take_error (ctx->result, error); + deactivate_context_complete (ctx); + return; + } + + /* Go on */ + ctx->step++; + deactivate_step (ctx); +} + +static void +deactivate_step (DeactivateContext *ctx) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (ctx->self); + GError *error = NULL; + + /* Check cancellable in each step */ + if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) { + g_simple_async_result_take_error (ctx->result, error); + deactivate_context_complete (ctx); + return; + } + + switch (ctx->step) { + case DEACTIVATE_CONTEXT_STEP_FIRST: + ctx->step++; + /* Fall down */ + + case DEACTIVATE_CONTEXT_STEP_CLEANUP: + /* Make sure we keep a ref to the PPP manager if there is one */ + 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); + ctx->step++; + /* Fall down */ + + case DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP: + /* If we have a PPP manager, stop it */ + if (ctx->ppp_manager) { + nm_ppp_manager_stop (ctx->ppp_manager, + ctx->cancellable, + (GAsyncReadyCallback) ppp_manager_stop_ready, + ctx); + return; + } + ctx->step++; + /* Fall down */ + + case DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT: + /* Disconnect asynchronously */ + NM_MODEM_GET_CLASS (ctx->self)->disconnect (ctx->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)); + deactivate_context_complete (ctx); + return; + } + + g_assert_not_reached (); +} + +void +nm_modem_deactivate_async (NMModem *self, + NMDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + DeactivateContext *ctx; + + ctx = g_slice_new0 (DeactivateContext); + ctx->self = g_object_ref (self); + ctx->device = g_object_ref (device); + ctx->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + nm_modem_deactivate_async); + ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + /* Start */ + ctx->step = DEACTIVATE_CONTEXT_STEP_FIRST; + deactivate_step (ctx); +} + +/*****************************************************************************/ + void nm_modem_deactivate (NMModem *self, NMDevice *device) { - NM_MODEM_GET_CLASS (self)->deactivate (self, device); + /* First cleanup */ + NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, device); + /* Then disconnect without waiting */ + NM_MODEM_GET_CLASS (self)->disconnect (self, FALSE, NULL, NULL, NULL); } /*****************************************************************************/ @@ -912,7 +1121,6 @@ nm_modem_device_state_changed (NMModem *self, switch (new_state) { case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: - case NM_DEVICE_STATE_DISCONNECTED: case NM_DEVICE_STATE_FAILED: if (priv->act_request) { cancel_get_secrets (self); @@ -924,7 +1132,9 @@ nm_modem_device_state_changed (NMModem *self, /* Don't bother warning on FAILED since the modem is already gone */ if (new_state == NM_DEVICE_STATE_FAILED) warn = FALSE; - NM_MODEM_GET_CLASS (self)->disconnect (self, warn); + /* First cleanup */ + NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, NULL); + NM_MODEM_GET_CLASS (self)->disconnect (self, warn, NULL, NULL, NULL); } break; default: @@ -1030,8 +1240,8 @@ nm_modem_init (NMModem *self) static GObject* constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) + guint n_construct_params, + GObjectConstructParam *construct_params) { GObject *object; NMModemPrivate *priv; @@ -1056,7 +1266,7 @@ constructor (GType type, return object; - err: +err: g_object_unref (object); return NULL; } @@ -1209,7 +1419,7 @@ nm_modem_class_init (NMModemClass *klass) klass->act_stage1_prepare = act_stage1_prepare; klass->stage3_ip6_config_request = stage3_ip6_config_request; - klass->deactivate = deactivate; + klass->deactivate_cleanup = deactivate_cleanup; /* Properties */ diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index 2a4d9173..2cace890 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -143,9 +143,16 @@ typedef struct { void (*set_mm_enabled) (NMModem *self, gboolean enabled); - void (*disconnect) (NMModem *self, gboolean warn); + void (*disconnect) (NMModem *self, + gboolean warn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*disconnect_finish) (NMModem *self, + GAsyncResult *res, + GError **error); - void (*deactivate) (NMModem *self, NMDevice *device); + void (*deactivate_cleanup) (NMModem *self, NMDevice *device); gboolean (*owns_port) (NMModem *self, const char *iface); @@ -218,6 +225,15 @@ gboolean nm_modem_get_secrets (NMModem *modem, void nm_modem_deactivate (NMModem *modem, NMDevice *device); +void nm_modem_deactivate_async (NMModem *self, + NMDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean nm_modem_deactivate_async_finish (NMModem *self, + GAsyncResult *res, + GError **error); + void nm_modem_device_state_changed (NMModem *modem, NMDeviceState new_state, NMDeviceState old_state, @@ -237,7 +253,7 @@ NMModemIPType nm_modem_get_supported_ip_types (NMModem *self); /* For the modem-manager only */ void nm_modem_emit_removed (NMModem *self); -NMModemIPType nm_modem_get_connection_ip_type (NMModem *self, +GArray *nm_modem_get_connection_ip_type (NMModem *self, NMConnection *connection, GError **error); @@ -246,6 +262,8 @@ void nm_modem_emit_ip6_config_result (NMModem *self, NMIP6Config *config, GError *error); +const gchar *nm_modem_ip_type_to_string (NMModemIPType ip_type); + G_END_DECLS #endif /* __NETWORKMANAGER_MODEM_H__ */ diff --git a/src/devices/wwan/wwan-exports.ver b/src/devices/wwan/wwan-exports.ver index c23ab24b..23412de6 100644 --- a/src/devices/wwan/wwan-exports.ver +++ b/src/devices/wwan/wwan-exports.ver @@ -5,6 +5,8 @@ global: nm_modem_check_connection_compatible; nm_modem_complete_connection; nm_modem_deactivate; + nm_modem_deactivate_async; + nm_modem_deactivate_async_finish; nm_modem_device_state_changed; nm_modem_get_capabilities; nm_modem_get_control_port; |