summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author(no author) <(no author)>2005-03-29 02:34:24 +0000
committer(no author) <(no author)@4912f4e0-d625-0410-9fb7-b9a5a253dbdc>2005-03-29 02:34:24 +0000
commit2df9a5ddf6d004cf5f218bb807733db1741931bc (patch)
treed7cd224c20254cd10137bfb5df7a364b29277b1e
parent68bcb9cceb5d87c2776e91efb680f9441ac92aa0 (diff)
This commit was manufactured by cvs2svn to create tagSTABLE_0_3_5_PRE_SLEEP
'STABLE_0_3_5_PRE_SLEEP'. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/tags/STABLE_0_3_5_PRE_SLEEP@519 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
-rw-r--r--ChangeLog49
-rw-r--r--configure.in4
-rw-r--r--info-daemon/NetworkManagerInfoDbus.c5
-rw-r--r--panel-applet/NMWirelessApplet.c8
-rw-r--r--src/NetworkManager.c4
-rw-r--r--src/NetworkManagerAP.c2
-rw-r--r--src/NetworkManagerAP.h2
-rw-r--r--src/NetworkManagerDevice.c485
-rw-r--r--src/NetworkManagerPolicy.c24
-rw-r--r--src/NetworkManagerUtils.c211
-rw-r--r--src/NetworkManagerUtils.h36
11 files changed, 684 insertions, 146 deletions
diff --git a/ChangeLog b/ChangeLog
index 6e5c821d2a..d5026bb2bf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,52 @@
+2005-03-28 Dan Williams <dcbw@redhat.com>
+
+ * Merge Peter Jones' completion patch, reducing latency and speeding
+ up wait times for device activation and wireless scanning
+
+
+2005-03-28 Dan Williams <dcbw@redhat.com>
+
+ Patch from Bill Moss:
+ * src/NetworkManagerPolicy.c
+ - (nm_policy_allowed_ap_list_update): merge properties
+ for all wireless devices on update, not just active device
+
+2005-03-28 Dan Williams <dcbw@redhat.com>
+
+ * panel-applet/NMWirelessApplet.c
+ - Add some more contributors to the About dialog
+
+2005-03-28 Dan Williams <dcbw@redhat.com>
+
+ * src/NetworkManagerDevice.c
+ - (mdio_read): Fix two bugs that caused all devices to fail
+ the MII carrier detection support checks
+
+2005-03-22 Dan Williams <dcbw@redhat.com>
+
+ Patch from Bill Moss:
+ * src/NetworkManagerInfoDbus.c
+ - (nmi_dbus_update_network_auth_method, nmi_dbus_get_network_properties):
+ free leaked GConf values
+
+2005-03-12 Dan Williams <dcbw@redhat.com>
+
+ Patch from Nathaniel McCallum:
+ * src/NetworkManagerDevice.c
+ - (nm_device_set_wireless_config): Increase timeout for some devices
+
+2005-03-04 Dan Williams <dcbw@redhat.com>
+
+ Patch from Peter Jones:
+ - Make stuff work with gcc 4.0
+
+2005-02-28 Dan Williams <dcbw@redhat.com>
+
+ Tag STABLE_0_3_4_RELEASE
+
+ * configure.in:
+ - Bump version to 0.3.4
+
2005-02-27 Jim Huang <jserv@kaffe.org>
* configure.in: Added "zh_TW" (Traditional Chinese) to ALL_LINGUAS.
diff --git a/configure.in b/configure.in
index f64b7c44f5..3b9a3d16f9 100644
--- a/configure.in
+++ b/configure.in
@@ -1,6 +1,6 @@
AC_PREREQ(2.52)
-AC_INIT(NetworkManager, 0.3.3, dcbw@redhat.com, NetworkManager)
+AC_INIT(NetworkManager, 0.3.4, dcbw@redhat.com, NetworkManager)
AM_INIT_AUTOMAKE([subdir-objects])
AM_MAINTAINER_MODE
@@ -243,7 +243,7 @@ if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then
AC_MSG_RESULT(yes)
CFLAGS="-Wall -Werror -std=gnu89 $CFLAGS"
- for option in -Wno-unused -Wno-strict-aliasing -Wno-sign-compare -Wdeclaration-after-statement; do
+ for option in -Wno-unused -Wno-strict-aliasing -Wno-sign-compare -Wdeclaration-after-statement -Wno-pointer-sign ; do
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $option"
AC_MSG_CHECKING([whether gcc understands $option])
diff --git a/info-daemon/NetworkManagerInfoDbus.c b/info-daemon/NetworkManagerInfoDbus.c
index 1cd5123754..6d4f88d395 100644
--- a/info-daemon/NetworkManagerInfoDbus.c
+++ b/info-daemon/NetworkManagerInfoDbus.c
@@ -486,7 +486,8 @@ static DBusMessage *nmi_dbus_get_network_properties (NMIAppInfo *info, DBusMessa
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, array, num_items,
DBUS_TYPE_INVALID);
}
- gconf_value_free (ap_addrs_value);
+ if (ap_addrs_value)
+ gconf_value_free (ap_addrs_value);
g_free (essid);
g_free (key);
@@ -538,6 +539,8 @@ static DBusMessage *nmi_dbus_update_network_auth_method (NMIAppInfo *info, DBusM
gconf_client_set_int (info->gconf_client, key, auth_method, NULL);
g_free (key);
}
+ if (value)
+ gconf_value_free (value);
g_free (escaped_network);
diff --git a/panel-applet/NMWirelessApplet.c b/panel-applet/NMWirelessApplet.c
index 90e6804d85..c3083037f1 100644
--- a/panel-applet/NMWirelessApplet.c
+++ b/panel-applet/NMWirelessApplet.c
@@ -121,10 +121,16 @@ void nmwa_about_cb (NMWirelessApplet *applet)
static const gchar *authors[] =
{
"The Red Hat Desktop Team, including:\n",
- "Dan Williams <dcbw@redhat.com>",
"Jonathan Blandford <jrb@redhat.com>",
"John Palmieri <johnp@redhat.com>",
+ "Ray Strode <rstrode@redhat.com>",
"Colin Walters <walters@redhat.com>",
+ "Dan Williams <dcbw@redhat.com>",
+ "\nAnd others, including:\n",
+ "Bill Moss",
+ "Tom Parker",
+ "j@bootlab.org",
+ "Peter Jones <pjones@redhat.com>",
NULL
};
diff --git a/src/NetworkManager.c b/src/NetworkManager.c
index 558c19eb6d..b89dbe6df5 100644
--- a/src/NetworkManager.c
+++ b/src/NetworkManager.c
@@ -591,8 +591,10 @@ static void nm_data_free (NMData *data)
static void sigterm_handler (int signum)
{
+ int ignore;
+
syslog (LOG_NOTICE, "Caught SIGINT/SIGTERM");
- write (nm_data->sigterm_pipe[1], "X", 1);
+ ignore = write (nm_data->sigterm_pipe[1], "X", 1);
}
static gboolean sigterm_pipe_handler (GIOChannel *src, GIOCondition condition, gpointer user_data)
diff --git a/src/NetworkManagerAP.c b/src/NetworkManagerAP.c
index 0bb80b5fee..f679c68f72 100644
--- a/src/NetworkManagerAP.c
+++ b/src/NetworkManagerAP.c
@@ -279,7 +279,7 @@ void nm_ap_set_encrypted (NMAccessPoint *ap, gboolean encrypted)
* Return the encryption method the user specified for this access point.
*
*/
-const NMEncKeyType nm_ap_get_enc_type (const NMAccessPoint *ap)
+NMEncKeyType nm_ap_get_enc_type (const NMAccessPoint *ap)
{
g_return_val_if_fail (ap != NULL, TRUE);
diff --git a/src/NetworkManagerAP.h b/src/NetworkManagerAP.h
index 2d32aee436..d190deb611 100644
--- a/src/NetworkManagerAP.h
+++ b/src/NetworkManagerAP.h
@@ -43,7 +43,7 @@ void nm_ap_set_essid (NMAccessPoint *ap, const char *essid);
char * nm_ap_get_enc_key_source (const NMAccessPoint *ap);
char * nm_ap_get_enc_key_hashed (const NMAccessPoint *ap);
void nm_ap_set_enc_key_source (NMAccessPoint *ap, const char *key, NMEncKeyType type);
-const NMEncKeyType nm_ap_get_enc_type (const NMAccessPoint *ap);
+NMEncKeyType nm_ap_get_enc_type (const NMAccessPoint *ap);
NMDeviceAuthMethod nm_ap_get_auth_method (const NMAccessPoint *ap);
void nm_ap_set_auth_method (NMAccessPoint *ap, const NMDeviceAuthMethod auth_method);
diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c
index b3d6f2576d..7b8cfca27f 100644
--- a/src/NetworkManagerDevice.c
+++ b/src/NetworkManagerDevice.c
@@ -46,6 +46,8 @@ static gboolean nm_device_activation_configure_ip (NMDevice *dev, gboolean do_on
static gboolean nm_device_wireless_scan (gpointer user_data);
static gboolean supports_mii_carrier_detect (NMDevice *dev);
static gboolean supports_ethtool_carrier_detect (NMDevice *dev);
+static gboolean nm_device_bring_up_wait (NMDevice *dev, gboolean cancelable);
+static gboolean nm_device_activation_handle_cancel (NMDevice *dev);
typedef struct
{
@@ -201,6 +203,7 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev,
{
NMDevice *dev;
GError *error = NULL;
+ char *msg;
g_return_val_if_fail (iface != NULL, NULL);
g_return_val_if_fail (strlen (iface) > 0, NULL);
@@ -250,8 +253,9 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev,
goto err;
/* Have to bring the device up before checking link status and other stuff */
- nm_device_bring_up (dev);
- g_usleep (G_USEC_PER_SEC);
+ nm_device_bring_up_wait (dev, 0);
+
+ /* Get driver support level */
dev->driver_support_level = nm_get_driver_support_level (dev->app_data->hal_ctx, dev);
/* Initialize wireless-specific options */
@@ -324,10 +328,12 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev,
}
/* Block until our device thread has actually had a chance to start. */
- syslog (LOG_ERR, "nm_device_new(): waiting for device's worker thread to start.\n");
- while (dev->worker_started == FALSE)
- g_usleep (G_USEC_PER_SEC / 2);
- syslog (LOG_ERR, "nm_device_new(): device's worker thread started, continuing.\n");
+ msg = g_strdup_printf ("%s: waiting for device's worker thread to start...", nm_device_get_iface (dev));
+ nm_wait_for_completion (NM_COMPLETION_TRIES_INFINITY,
+ G_USEC_PER_SEC / 20, nm_completion_boolean_test, NULL,
+ &dev->worker_started, msg, LOG_INFO, 0);
+ g_free (msg);
+ syslog (LOG_ERR, "%s: device's worker thread started, continuing.\n", nm_device_get_iface (dev));
return (dev);
@@ -349,6 +355,7 @@ void nm_device_ref (NMDevice *dev)
dev->refcount++;
}
+
/*
* nm_device_unref
*
@@ -367,10 +374,8 @@ gboolean nm_device_unref (NMDevice *dev)
dev->refcount--;
if (dev->refcount <= 0)
{
- if (dev->loop)
- g_main_loop_quit (dev->loop);
- while (dev->worker_done == FALSE)
- g_usleep (300);
+ nm_device_worker_thread_stop (dev);
+ nm_device_bring_down (dev);
if (nm_device_is_wireless (dev))
{
@@ -418,8 +423,6 @@ static gpointer nm_device_worker (gpointer user_data)
exit (1);
}
- dev->worker_started = TRUE;
-
/* Do an initial wireless scan */
if (nm_device_is_wireless (dev))
{
@@ -431,6 +434,7 @@ static gpointer nm_device_worker (gpointer user_data)
g_source_unref (source);
}
+ dev->worker_started = TRUE;
g_main_loop_run (dev->loop);
/* Remove any DHCP timeouts that might have been running */
@@ -454,9 +458,11 @@ void nm_device_worker_thread_stop (NMDevice *dev)
{
g_return_if_fail (dev != NULL);
- g_main_loop_quit (dev->loop);
- while (dev->worker_done == FALSE)
- g_usleep (G_USEC_PER_SEC / 2);
+ if (dev->loop)
+ g_main_loop_quit (dev->loop);
+ nm_wait_for_completion(NM_COMPLETION_TRIES_INFINITY, 300,
+ nm_completion_boolean_test, NULL, &dev->worker_done,
+ NULL, NULL, 0);
}
@@ -1513,20 +1519,6 @@ static void nm_device_set_up_down (NMDevice *dev, gboolean up)
* Interface state functions: bring up, down, check
*
*/
-void nm_device_bring_up (NMDevice *dev)
-{
- g_return_if_fail (dev != NULL);
-
- nm_device_set_up_down (dev, TRUE);
-}
-
-void nm_device_bring_down (NMDevice *dev)
-{
- g_return_if_fail (dev != NULL);
-
- nm_device_set_up_down (dev, FALSE);
-}
-
gboolean nm_device_is_up (NMDevice *dev)
{
int sk;
@@ -1553,6 +1545,90 @@ gboolean nm_device_is_up (NMDevice *dev)
return (FALSE);
}
+gboolean nm_completion_device_is_up_test (int tries, va_list args)
+{
+ NMDevice *dev = va_arg (args, NMDevice *);
+ gboolean *err = va_arg (args, gboolean *);
+ gboolean cancelable = va_arg (args, gboolean);
+
+ g_return_val_if_fail (dev != NULL, TRUE);
+ g_return_val_if_fail (err != NULL, TRUE);
+
+ *err = FALSE;
+ if (cancelable && nm_device_activation_handle_cancel (dev))
+ {
+ *err = TRUE;
+ return TRUE;
+ }
+ if (nm_device_is_up (dev))
+ return TRUE;
+ return FALSE;
+}
+
+void nm_device_bring_up (NMDevice *dev)
+{
+ g_return_if_fail (dev != NULL);
+
+ nm_device_set_up_down (dev, TRUE);
+}
+
+gboolean nm_device_bring_up_wait (NMDevice *dev, gboolean cancelable)
+{
+ gboolean err = FALSE;
+
+ g_return_val_if_fail (dev != NULL, TRUE);
+
+ nm_device_bring_up (dev);
+ nm_wait_for_completion (400, G_USEC_PER_SEC / 200, NULL,
+ nm_completion_device_is_up_test, dev,
+ &err, cancelable);
+ if (err)
+ syslog (LOG_INFO, "failed to bring device up");
+ return err;
+}
+
+void nm_device_bring_down (NMDevice *dev)
+{
+ g_return_if_fail (dev != NULL);
+
+ nm_device_set_up_down (dev, FALSE);
+}
+
+gboolean nm_completion_device_is_down_test(int tries, va_list args)
+{
+ NMDevice *dev = va_arg (args, NMDevice *);
+ gboolean *err = va_arg (args, gboolean *);
+ gboolean cancelable = va_arg (args, gboolean);
+
+ g_return_val_if_fail (dev != NULL, TRUE);
+ g_return_val_if_fail (err != NULL, TRUE);
+
+ *err = FALSE;
+ if (cancelable && nm_device_activation_handle_cancel (dev))
+ {
+ *err = TRUE;
+ return TRUE;
+ }
+ if (!nm_device_is_up (dev))
+ return TRUE;
+ return FALSE;
+}
+
+gboolean nm_device_bring_down_wait (NMDevice *dev, gboolean cancelable)
+{
+ gboolean err = FALSE;
+
+ g_return_val_if_fail (dev != NULL, TRUE);
+
+ nm_device_bring_down (dev);
+ nm_wait_for_completion (400, G_USEC_PER_SEC / 200, NULL,
+ nm_completion_device_is_down_test, dev,
+ &err, cancelable);
+ if (err)
+ syslog (LOG_INFO, "failed to bring device down");
+ return err;
+}
+
/*
* nm_device_get_mode
@@ -1749,6 +1825,46 @@ static gboolean nm_device_activation_handle_cancel (NMDevice *dev)
return (FALSE);
}
+static gboolean nm_dwwfl_test (int tries, va_list args)
+{
+ NMDevice *dev = va_arg (args, NMDevice *);
+ guint *assoc_count = va_arg (args, guint *);
+ double *last_freq = va_arg (args, double *);
+ char *essid = va_arg (args, char *);
+ int required = va_arg (args, int);
+
+ double cur_freq = nm_device_get_frequency (dev);
+ gboolean assoc = nm_device_wireless_is_associated (dev);
+ const char * cur_essid = nm_device_get_essid (dev);
+
+ /* If we've been cancelled, return that we should stop */
+ if (nm_device_activation_should_cancel (dev))
+ return TRUE;
+
+ /* If we're on the same frequency and essid, and we're associated,
+ * increment the count for how many iterations we've been associated;
+ * otherwise start over. */
+ /* XXX floating point comparison this way is dangerous, IIRC */
+ if ((cur_freq == *last_freq) && assoc && !strcmp (essid, cur_essid))
+ {
+ (*assoc_count)++;
+ }
+ else
+ {
+ *assoc_count = 0;
+ *last_freq = cur_freq;
+ }
+
+ /* If we're told to cancel, return that we're finished.
+ * If we've the frequency has been stable for more than the required
+ * interval, return that we're finished.
+ * Otherwise, we're not finished. */
+ if (nm_device_activation_should_cancel (dev) || *assoc_count >= required)
+ return TRUE;
+
+ return FALSE;
+}
+
/*
* nm_device_wireless_wait_for_link
@@ -1759,59 +1875,72 @@ static gboolean nm_device_activation_handle_cancel (NMDevice *dev)
*/
static gboolean nm_device_wireless_wait_for_link (NMDevice *dev, const char *essid)
{
- struct timeval end_time;
- struct timeval cur_time;
- gboolean link = FALSE;
+ guint assoc = 0;
double last_freq = 0;
guint assoc_count = 0;
- gint pause_value;
+ struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
+
+ /* we want to sleep for a very short amount of time, to minimize
+ * hysteresis on the boundaries of our required time. But we
+ * also want the maximum to be based on what the card */
+ const guint delay = 30;
+ const guint required_tries = 10;
+ const guint min_delay = 2 * (required_tries / delay);
g_return_val_if_fail (dev != NULL, FALSE);
g_return_val_if_fail (time > 0, FALSE);
- pause_value = nm_device_get_association_pause_value (dev);
- if (pause_value < 1)
- return FALSE;
-
- gettimeofday (&end_time, NULL);
- end_time.tv_sec += pause_value;
+ /* for cards which don't scan many frequencies, this will return
+ * 5 seconds, which we'll bump up to 6 seconds below. Oh well. */
+ timeout.tv_sec = (time_t)nm_device_get_association_pause_value (dev);
- /* We more or less keep asking the driver for the frequency the card is on, and
- * when the frequency has stabilized (the driver has to scan channels to find the AP,
- * and when it finds the AP it stops scanning) and the MAC is valid, we think we
- * have a link.
- */
- gettimeofday (&cur_time, NULL);
- while (cur_time.tv_sec < end_time.tv_sec)
- {
- double cur_freq = nm_device_get_frequency (dev);
- gboolean assoc = nm_device_wireless_is_associated (dev);
- char *cur_essid = nm_device_get_essid (dev);
+ /* Refuse to to have a timeout that's _less_ than twice the total time
+ * required before calling a link valid */
+ if (timeout.tv_sec < min_delay)
+ timeout.tv_sec = min_delay;
- if ((cur_freq == last_freq) && assoc && !strcmp (essid, cur_essid))
- assoc_count++;
- else
- assoc_count = 0;
- last_freq = cur_freq;
+ /* We more or less keep asking the driver for the frequency the
+ * card is listening on until it connects to an AP. Once it's
+ * associated, the driver stops scanning. To detect that, we look
+ * for the essid and frequency to remain constant for 3 seconds.
+ * When it remains constant, we assume it's a real link. */
+ nm_wait_for_timeout (&timeout, G_USEC_PER_SEC / delay,
+ nm_dwwfl_test, nm_dwwfl_test, dev, &assoc,
+ &last_freq, essid, required_tries * 2);
- g_usleep (G_USEC_PER_SEC / 2);
- if (nm_device_activation_should_cancel (dev))
- break;
+ /* If we've had a reasonable association count, we say we have a link */
+ if (assoc > required_tries)
+ return TRUE;
+ return FALSE;
+}
- gettimeofday (&cur_time, NULL);
- if ((cur_time.tv_sec >= end_time.tv_sec) && (cur_time.tv_usec >= end_time.tv_usec))
- break;
+static gboolean nm_device_link_test(int tries, va_list args)
+{
+ NMDevice *dev = va_arg(args, NMDevice *);
+ gboolean *err = va_arg(args, gboolean *);
- /* Assume that if we've been associated this long, we might as well just stop. */
- if (assoc_count >= 9)
- break;
+ g_return_val_if_fail(dev != NULL, TRUE);
+ g_return_val_if_fail(err != NULL, TRUE);
+
+ if (nm_device_wireless_is_associated (dev) && nm_device_get_essid (dev))
+ {
+ *err = FALSE;
+ return TRUE;
}
+ *err = TRUE;
+ return FALSE;
+}
- /* If we've had a reasonable association count, we say we have a link */
- if (assoc_count > 6)
- link = TRUE;
+static gboolean nm_device_is_up_and_associated_wait (NMDevice *dev, int timeout, int interval)
+{
+ gboolean err;
+ const gint delay = (G_USEC_PER_SEC * nm_device_get_association_pause_value (dev)) / interval;
+ const gint max_cycles = timeout * interval;
- return (link);
+ g_return_val_if_fail (dev != NULL, TRUE);
+
+ nm_wait_for_completion (max_cycles, delay, NULL, nm_device_link_test, dev, &err);
+ return !err;
}
@@ -1836,10 +1965,9 @@ static gboolean nm_device_set_wireless_config (NMDevice *dev, NMAccessPoint *ap)
g_return_val_if_fail (nm_ap_get_auth_method (ap) != NM_DEVICE_AUTH_METHOD_UNKNOWN, FALSE);
/* Force the card into Managed/Infrastructure mode */
- nm_device_bring_down (dev);
- g_usleep (G_USEC_PER_SEC * 2);
- nm_device_bring_up (dev);
- g_usleep (G_USEC_PER_SEC * 2);
+ nm_device_bring_down_wait (dev, 0);
+ nm_device_bring_up_wait (dev, 0);
+
nm_device_set_mode (dev, NETWORK_MODE_INFRA);
essid = nm_ap_get_essid (ap);
@@ -1877,8 +2005,11 @@ static gboolean nm_device_set_wireless_config (NMDevice *dev, NMAccessPoint *ap)
((auth == NM_DEVICE_AUTH_METHOD_OPEN_SYSTEM) ? "Open System" :
((auth == NM_DEVICE_AUTH_METHOD_SHARED_KEY) ? "Shared Key" : "unknown")));
- /* Bring the device up and pause to allow card to associate. */
- g_usleep (G_USEC_PER_SEC * 2);
+ /* Bring the device up and pause to allow card to associate. After we set the ESSID
+ * on the card, the card has to scan all channels to find our requested AP (which can
+ * take a long time if it is an A/B/G chipset like the Atheros 5212, for example).
+ */
+ nm_device_is_up_and_associated_wait (dev, 2, 100);
/* Some cards don't really work well in ad-hoc mode unless you explicitly set the bitrate
* on them. (Netgear WG511T/Atheros 5212 with madwifi drivers). Until we can get rate information
@@ -2070,6 +2201,41 @@ void invalidate_ap (NMDevice *dev, NMAccessPoint *ap)
}
+/* this gets called without the scan mutex held */
+static gboolean nm_wa_test (int tries, va_list args)
+{
+ NMDevice *dev = va_arg(args, NMDevice *);
+ NMAccessPoint **best_ap = va_arg(args, NMAccessPoint **);
+ gboolean *err = va_arg(args, gboolean *);
+
+ g_return_val_if_fail(dev != NULL, TRUE);
+ g_return_val_if_fail(best_ap != NULL, TRUE);
+ g_return_val_if_fail(err != NULL, TRUE);
+
+ *err = TRUE;
+ if (nm_device_activation_handle_cancel(dev))
+ return TRUE;
+
+ if (tries % 100 == 0)
+ syslog (LOG_INFO, "Activation (%s/wireless): waiting for access point. (attempt %d)", nm_device_get_iface(dev), tries);
+
+ *best_ap = nm_device_get_best_ap (dev);
+ if (*best_ap) {
+ /* Set ESSID early so that when we send out the
+ * DeviceStatusChanged signal below, we are able to
+ * respond correctly to queries for "getActiveNetwork"
+ * against our device. nm_device_get_path_for_ap() uses
+ * the /card's/ AP, not the best_ap. */
+ nm_device_set_essid (dev, nm_ap_get_essid (*best_ap));
+ nm_device_set_now_scanning (dev, FALSE);
+ *err = FALSE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
/*
* nm_device_activate_wireless
*
@@ -2080,12 +2246,13 @@ void invalidate_ap (NMDevice *dev, NMAccessPoint *ap)
*/
static gboolean nm_device_activate_wireless (NMDevice *dev)
{
- NMAccessPoint *best_ap;
+ NMAccessPoint *best_ap = NULL;
gboolean success = FALSE;
guint8 attempt = 1;
char last_essid [50] = "\0";
gboolean need_key = FALSE;
gboolean found_ap = FALSE;
+ gboolean err = FALSE;
g_return_val_if_fail (dev != NULL, FALSE);
g_return_val_if_fail (dev->app_data != NULL, FALSE);
@@ -2095,9 +2262,7 @@ static gboolean nm_device_activate_wireless (NMDevice *dev)
*/
nm_lock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__);
- if (!nm_device_is_up (dev))
- nm_device_bring_up (dev);
- g_usleep (G_USEC_PER_SEC);
+ nm_device_bring_up_wait (dev, 1);
get_ap:
/* If we were told to quit activation, stop the thread and return */
@@ -2108,24 +2273,19 @@ get_ap:
* lock here because this might take a while.
*/
nm_unlock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__);
- while (!(best_ap = nm_device_get_best_ap (dev)))
- {
- nm_device_set_now_scanning (dev, TRUE);
- if (!found_ap)
- syslog (LOG_ERR, "Activation (%s/wireless): waiting for an access point.", nm_device_get_iface (dev));
- g_usleep (G_USEC_PER_SEC * 2);
- /* If we were told to quit activation, stop the thread and return */
- if (nm_device_activation_handle_cancel (dev))
- {
- /* Wierd as it may seem, we lock here to balance the unlock in "out:" */
- nm_lock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__);
- goto out;
- }
- found_ap = TRUE;
+ /* Get a valid "best" access point we should connect to. */
+ nm_device_set_now_scanning (dev, TRUE);
+
+ /* at most wait 10 seconds, but check every 50th to see if we're done */
+ nm_wait_for_completion(NM_COMPLETION_TRIES_INFINITY, G_USEC_PER_SEC / 50, nm_wa_test, NULL, dev, &best_ap, &err);
+ if (err)
+ {
+ /* Wierd as it may seem, we lock here to balance the unlock in "out:" */
+ nm_lock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__);
+ goto out;
}
- if (found_ap)
- syslog (LOG_ERR, "Activation (%s/wireless): found access point '%s' to use.", nm_device_get_iface (dev), nm_ap_get_essid (best_ap));
+ syslog (LOG_ERR, "Activation (%s/wireless): found access point '%s' to use.", nm_device_get_iface (dev), nm_ap_get_essid (best_ap));
/* Set ESSID early so that when we send out the DeviceStatusChanged signal below,
* we are able to respond correctly to queries for "getActiveNetwork" against
@@ -2155,6 +2315,8 @@ get_ap:
need_key = AP_NEED_KEY (dev, best_ap);
need_key:
+ if (nm_device_activation_handle_cancel (dev))
+ goto out;
if (need_key)
{
char *essid = nm_ap_get_essid (best_ap);
@@ -2250,8 +2412,15 @@ try_connect:
* and also for Open System mode (where you cannot know WEP key is wrong ever), we try to
* do DHCP and if that fails, fall back to next auth mode and try again.
*/
+ success = FALSE;
if ((success = nm_device_activation_configure_ip (dev, adhoc)))
{
+ if (nm_device_activation_handle_cancel (dev))
+ {
+ success = FALSE;
+ goto out;
+ }
+
/* Cache the last known good auth method in both NetworkManagerInfo and our allowed AP list */
nm_dbus_update_network_auth_method (dev->app_data->dbus_connection, nm_ap_get_essid (best_ap), nm_ap_get_auth_method (best_ap));
if ((tmp_ap = nm_ap_list_get_ap_by_essid (dev->app_data->allowed_ap_list, nm_ap_get_essid (best_ap))))
@@ -2259,7 +2428,6 @@ try_connect:
}
else
{
- /* If we were told to quit activation, stop the thread and return */
if (nm_device_activation_handle_cancel (dev))
goto out;
@@ -2291,7 +2459,10 @@ try_connect:
connect_done:
/* If we were told to quit activation, stop the thread and return */
if (nm_device_activation_handle_cancel (dev))
+ {
+ success = FALSE;
goto out;
+ }
if (success)
{
@@ -2458,6 +2629,35 @@ gboolean nm_device_activation_should_cancel (NMDevice *dev)
}
+static gboolean nm_ac_test (int tries, va_list args)
+{
+ NMDevice *dev = va_arg (args, NMDevice *);
+
+ g_return_val_if_fail (dev != NULL, TRUE);
+
+ if (tries == 0 && nm_device_get_dhcp_iface (dev))
+ nm_device_dhcp_cease (dev);
+
+ if (nm_device_is_activating(dev))
+ {
+ /* Nice race here between quit activation and dhcp. We may
+ * not have started DHCP when we're told to quit activation,
+ * so we need to keep signalling dhcp to quit, which it will
+ * pick up whenever it starts.
+ *
+ * This should really be taken care of a better way.
+ */
+ if (nm_device_get_dhcp_iface (dev))
+ nm_device_dhcp_cease (dev);
+ if (tries % 20 == 0)
+ syslog (LOG_DEBUG, "Activation (%s/wireless): waiting on dhcp to cease or device to finish activation", nm_device_get_iface(dev));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
/*
* nm_device_activation_cancel
*
@@ -2477,18 +2677,7 @@ void nm_device_activation_cancel (NMDevice *dev)
* The other problem with waiting here is that we hold up dbus traffic
* that we should respond to.
*/
- while (nm_device_is_activating (dev))
- {
- /* Nice race here between quit activation and dhcp. We may not have
- * started DHCP when we're told to quit activation, so we need to keep
- * signalling dhcp to quit, which it will pick up whenever it starts.
- * This should really be taken care of a better way.
- */
- if (dev->dhcp_iface)
- nm_device_dhcp_cease (dev);
-
- g_usleep (G_USEC_PER_SEC / 2);
- }
+ nm_wait_for_completion(NM_COMPLETION_TRIES_INFINITY, G_USEC_PER_SEC / 20, nm_ac_test, NULL, dev);
syslog (LOG_DEBUG, "nm_device_activation_cancel(%s): cancelled.", nm_device_get_iface (dev));
}
}
@@ -3111,7 +3300,7 @@ static void nm_device_do_pseudo_scan (NMDevice *dev)
nm_device_set_essid (dev, nm_ap_get_essid (ap));
/* Wait a bit for association */
- g_usleep (G_USEC_PER_SEC * nm_device_get_association_pause_value (dev));
+ nm_device_is_up_and_associated_wait (dev, 2, 100);
/* Do we have a valid MAC address? */
nm_device_get_ap_address (dev, &cur_ap_addr);
@@ -3419,6 +3608,44 @@ static gboolean nm_device_wireless_process_scan_results (gpointer user_data)
}
+static gboolean nm_completion_scan_has_results (int tries, va_list args)
+{
+ NMDevice *dev = va_arg (args, NMDevice *);
+ gboolean *err = va_arg (args, gboolean *);
+ int sk = va_arg (args, int);
+ NMWirelessScanResults *scan_results = va_arg (args, NMWirelessScanResults *);
+ int rc;
+
+ g_return_val_if_fail (dev != NULL, TRUE);
+ g_return_val_if_fail (err != NULL, TRUE);
+ g_return_val_if_fail (scan_results != NULL, TRUE);
+
+ rc = iw_scan(sk, (char *)nm_device_get_iface (dev), WIRELESS_EXT, &(scan_results->scan_head));
+ if (rc == -1 && errno == ETIME)
+ {
+ syslog (LOG_DEBUG, "Warning: the wireless card (%s) requires too much time for scans. Its driver needs to be fixed.", nm_device_get_iface (dev));
+ scan_results->scan_head.result = NULL;
+ *err = TRUE;
+ return TRUE;
+ }
+ *err = FALSE;
+ if ((rc == -1 && errno == ENODATA) || (rc == 0 && scan_results->scan_head.result == NULL))
+ {
+ /* Card hasn't had time yet to compile full access point list.
+ * Give it some more time and scan again. If that doesn't
+ * work, we eventually give up. */
+ scan_results->scan_head.result = NULL;
+ return FALSE;
+ }
+ else if (rc == -1)
+ {
+ scan_results->scan_head.result = NULL;
+ return TRUE;
+ }
+ return TRUE;
+}
+
+
/*
* nm_device_wireless_scan
*
@@ -3449,17 +3676,24 @@ static gboolean nm_device_wireless_scan (gpointer user_data)
/* Grab the scan mutex */
if (nm_try_acquire_mutex (dev->options.wireless.scan_mutex, __FUNCTION__))
{
+ gboolean devup_err;
+
/* Device must be up before we can scan */
- if (!nm_device_is_up (dev))
- nm_device_bring_up (dev);
- g_usleep (G_USEC_PER_SEC);
+ devup_err = nm_device_bring_up_wait(dev, 1);
+ if (devup_err)
+ {
+ nm_unlock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__);
+ nm_device_wireless_schedule_scan (dev);
+ return FALSE;
+ }
if ((sk = iw_sockets_open ()) >= 0)
{
- int err;
- NMNetworkMode orig_mode = NETWORK_MODE_INFRA;
- double orig_freq = 0;
- int orig_rate = 0;
+ int err;
+ NMNetworkMode orig_mode = NETWORK_MODE_INFRA;
+ double orig_freq = 0;
+ int orig_rate = 0;
+ const int max_wait = G_USEC_PER_SEC * nm_device_get_association_pause_value (dev) /2;
orig_mode = nm_device_get_mode (dev);
if (orig_mode == NETWORK_MODE_ADHOC)
@@ -3475,20 +3709,9 @@ static gboolean nm_device_wireless_scan (gpointer user_data)
nm_device_set_frequency (dev, 0);
scan_results = g_malloc0 (sizeof (NMWirelessScanResults));
- err = iw_scan (sk, (char *)nm_device_get_iface (dev), WIRELESS_EXT, &(scan_results->scan_head));
- if ((err == -1) && (errno == ENODATA))
- {
- /* Card hasn't had time yet to compile full access point list.
- * Give it some more time and scan again. If that doesn't work
- * give up.
- */
- g_usleep ((G_USEC_PER_SEC * nm_device_get_association_pause_value (dev)) / 2);
- err = iw_scan (sk, (char *)nm_device_get_iface (dev), WIRELESS_EXT, &(scan_results->scan_head));
- if (err == -1)
- scan_results->scan_head.result = NULL;
- }
- else if ((err == -1) && (errno == ETIME))
- syslog (LOG_ERR, "Warning: the wireless card (%s) requires too much time for scans. Its driver needs to be fixed.", nm_device_get_iface (dev));
+ nm_wait_for_completion(max_wait, max_wait/20,
+ nm_completion_scan_has_results, NULL,
+ dev, &err, sk, scan_results);
nm_device_set_mode (dev, orig_mode);
/* Only set frequency if ad-hoc mode */
@@ -3650,13 +3873,13 @@ static int mdio_read (int sk, struct ifreq *ifr, int location)
{
struct mii_ioctl_data *mii;
- g_return_val_if_fail (sk < 0, -1);
+ g_return_val_if_fail (sk >= 0, -1);
g_return_val_if_fail (ifr != NULL, -1);
mii = (struct mii_ioctl_data *) &(ifr->ifr_data);
mii->reg_num = location;
- if (ioctl (sk, SIOCGMIIREG, &ifr) < 0)
+ if (ioctl (sk, SIOCGMIIREG, ifr) < 0)
return -1;
return (mii->val_out);
diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c
index 71910fdf68..ea013e272c 100644
--- a/src/NetworkManagerPolicy.c
+++ b/src/NetworkManagerPolicy.c
@@ -468,7 +468,8 @@ void nm_policy_schedule_device_switch (NMDevice *switch_to_dev, NMData *app_data
*/
static gboolean nm_policy_allowed_ap_list_update (gpointer user_data)
{
- NMData *data = (NMData *)user_data;
+ NMData *data = (NMData *)user_data;
+ GSList *elt;
g_return_val_if_fail (data != NULL, FALSE);
@@ -481,6 +482,20 @@ static gboolean nm_policy_allowed_ap_list_update (gpointer user_data)
if (data->allowed_ap_list)
nm_ap_list_populate_from_nmi (data->allowed_ap_list, data);
+ for (elt = data->dev_list; elt != NULL; elt = g_slist_next (elt))
+ {
+ NMDevice *dev = (NMDevice *)(elt->data);
+ if (nm_device_is_wireless (dev))
+ {
+ /* Once we have the list, copy in any relevant information from our Allowed list and fill
+ * in the ESSID of base stations that aren't broadcasting their ESSID, if we have their
+ * MAC address in our allowed list.
+ */
+ nm_ap_list_copy_essids_by_address (nm_device_ap_list_get (dev), data->allowed_ap_list);
+ nm_ap_list_copy_properties (nm_device_ap_list_get (dev), data->allowed_ap_list);
+ }
+ }
+
/* If the active device doesn't have a best_ap already, make it update to
* get the new data.
*/
@@ -490,13 +505,6 @@ static gboolean nm_policy_allowed_ap_list_update (gpointer user_data)
{
NMAccessPoint *best_ap;
- /* Once we have the list, copy in any relevant information from our Allowed list and fill
- * in the ESSID of base stations that aren't broadcasting their ESSID, if we have their
- * MAC address in our allowed list.
- */
- nm_ap_list_copy_essids_by_address (nm_device_ap_list_get (data->active_device), data->allowed_ap_list);
- nm_ap_list_copy_properties (nm_device_ap_list_get (data->active_device), data->allowed_ap_list);
-
best_ap = nm_device_get_best_ap (data->active_device);
if (!best_ap)
nm_device_update_best_ap (data->active_device);
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 77b908c32a..940ca9dfd9 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -423,3 +423,214 @@ NMDriverSupportLevel nm_get_driver_support_level (LibHalContext *ctx, NMDevice *
g_free (driver);
return (level);
}
+
+static inline int nm_timeval_cmp(const struct timeval *a,
+ const struct timeval *b)
+{
+ int x;
+ x = a->tv_sec - b->tv_sec;
+ x *= G_USEC_PER_SEC;
+ if (x)
+ return x;
+ x = a->tv_usec - b->tv_usec;
+ if (x)
+ return x;
+ return 0;
+}
+
+static inline int nm_timeval_has_passed(const struct timeval *a)
+{
+ struct timeval current;
+
+ gettimeofday(&current, NULL);
+
+ return (nm_timeval_cmp(&current, a) >= 0);
+}
+
+static inline void nm_timeval_add(struct timeval *a,
+ const struct timeval *b)
+{
+ struct timeval b1;
+
+ memmove(&b1, b, sizeof b1);
+
+ /* normalize a and b to be positive for everything */
+ while (a->tv_usec < 0)
+ {
+ a->tv_sec--;
+ a->tv_usec += G_USEC_PER_SEC;
+ }
+ while (b1.tv_usec < 0)
+ {
+ b1.tv_sec--;
+ b1.tv_usec += G_USEC_PER_SEC;
+ }
+
+ /* now add secs and usecs */
+ a->tv_sec += b1.tv_sec;
+ a->tv_usec += b1.tv_usec;
+
+ /* and handle our overflow */
+ if (a->tv_usec > G_USEC_PER_SEC)
+ {
+ a->tv_sec++;
+ a->tv_usec -= G_USEC_PER_SEC;
+ }
+}
+
+static void nm_v_wait_for_completion_or_timeout(
+ const int max_tries,
+ const struct timeval *max_time,
+ const guint interval_usecs,
+ nm_completion_func test_func,
+ nm_completion_func action_func,
+ va_list args)
+{
+ int try;
+ gboolean finished = FALSE;
+ struct timeval finish_time;
+
+ g_return_if_fail (test_func || action_func);
+
+ if (max_time) {
+ gettimeofday(&finish_time, NULL);
+ nm_timeval_add(&finish_time, max_time);
+ }
+
+ try = -1;
+ while (!finished &&
+ (max_tries == NM_COMPLETION_TRIES_INFINITY || try < max_tries))
+ {
+ if (max_time && nm_timeval_has_passed(&finish_time))
+ break;
+ try++;
+ if (test_func)
+ {
+ finished = (*test_func)(try, args);
+ if (finished)
+ break;
+ }
+
+#if 0
+#define NM_SLEEP_DEBUG
+#endif
+#ifdef NM_SLEEP_DEBUG
+ syslog (LOG_INFO, "sleeping or %d usecs", interval_usecs);
+#endif
+ g_usleep(interval_usecs);
+ if (action_func)
+ finished = (*action_func)(try, args);
+ }
+}
+
+void nm_wait_for_completion_or_timeout(
+ const int max_tries,
+ const struct timeval *max_time,
+ const guint interval_usecs,
+ nm_completion_func test_func,
+ nm_completion_func action_func,
+ ...)
+{
+ va_list ap;
+ va_start(ap, action_func);
+
+ nm_v_wait_for_completion_or_timeout(max_tries, max_time,
+ interval_usecs, test_func,
+ action_func, ap);
+ va_end(ap);
+}
+
+void nm_wait_for_completion(
+ const int max_tries,
+ const guint interval_usecs,
+ nm_completion_func test_func,
+ nm_completion_func action_func,
+ ...)
+{
+ va_list ap;
+ va_start(ap, action_func);
+
+ nm_v_wait_for_completion_or_timeout(max_tries, NULL,
+ interval_usecs, test_func,
+ action_func, ap);
+ va_end(ap);
+}
+
+void nm_wait_for_timeout(
+ const struct timeval *max_time,
+ const guint interval_usecs,
+ nm_completion_func test_func,
+ nm_completion_func action_func,
+ ...)
+{
+ va_list ap;
+ va_start(ap, action_func);
+
+ nm_v_wait_for_completion_or_timeout(-1, max_time,
+ interval_usecs, test_func,
+ action_func, ap);
+ va_end(ap);
+}
+
+/* you can use these, but they're really just examples */
+gboolean nm_completion_boolean_test(int tries, va_list args)
+{
+ gboolean *condition = va_arg(args, gboolean *);
+ char *message = va_arg(args, char *);
+ int log_level = va_arg(args, int);
+ int log_interval = va_arg(args, int);
+
+ g_return_val_if_fail (condition != NULL, TRUE);
+
+ if (message)
+ if ((log_interval == 0 && tries == 0) || (log_interval != 0 && tries % log_interval == 0))
+ syslog (log_level, message);
+
+ if (*condition)
+ return TRUE;
+ return FALSE;
+}
+
+gboolean nm_completion_boolean_function1_test(int tries, va_list args)
+{
+ nm_completion_boolean_function_1 condition =
+ va_arg(args, nm_completion_boolean_function_1);
+ char *message = va_arg(args, char *);
+ int log_level = va_arg(args, int);
+ int log_interval = va_arg(args, int);
+ u_int64_t arg0 = va_arg(args, unsigned long long);
+
+ g_return_val_if_fail (condition, TRUE);
+
+ if (message)
+ if ((log_interval == 0 && tries == 0)
+ || (log_interval != 0 && tries % log_interval == 0))
+ syslog(log_level, message);
+
+ if (!(*condition)(arg0))
+ return TRUE;
+ return FALSE;
+}
+
+gboolean nm_completion_boolean_function2_test(int tries, va_list args)
+{
+ nm_completion_boolean_function_2 condition =
+ va_arg(args, nm_completion_boolean_function_2);
+ char *message = va_arg(args, char *);
+ int log_level = va_arg(args, int);
+ int log_interval = va_arg(args, int);
+ u_int64_t arg0 = va_arg(args, unsigned long long);
+ u_int64_t arg1 = va_arg(args, unsigned long long);
+
+ g_return_val_if_fail (condition, TRUE);
+
+ if (message)
+ if ((log_interval == 0 && tries == 0)
+ || (log_interval != 0 && tries % log_interval == 0))
+ syslog(log_level, message);
+
+ if (!(*condition)(arg0, arg1))
+ return TRUE;
+ return FALSE;
+}
+
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index b46c89c318..7a9d1c1cc1 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -27,6 +27,8 @@
#include <syslog.h>
#include <net/ethernet.h>
#include <iwlib.h>
+#include <sys/time.h>
+#include <stdarg.h>
#include "NetworkManager.h"
#include "NetworkManagerMain.h"
@@ -48,4 +50,38 @@ int nm_spawn_process (char *args);
NMDriverSupportLevel nm_get_driver_support_level (LibHalContext *ctx, NMDevice *dev);
+#define NM_COMPLETION_TRIES_INFINITY -1
+
+typedef gboolean (*nm_completion_func)(int tries, va_list args);
+typedef gboolean (*nm_completion_boolean_function_1)(u_int64_t arg);
+typedef gboolean (*nm_completion_boolean_function_2)(
+ u_int64_t arg0, u_int64_t arg1);
+
+void nm_wait_for_completion(
+ const int max_tries,
+ const guint interval_usecs,
+ nm_completion_func test_func,
+ nm_completion_func action_func,
+ ...);
+
+void nm_wait_for_completion_or_timeout(
+ const int max_tries,
+ const struct timeval *max_time,
+ const guint interval_usecs,
+ nm_completion_func test_func,
+ nm_completion_func action_func,
+ ...);
+
+void nm_wait_for_timeout(
+ const struct timeval *max_time,
+ const guint interval_usecs,
+ nm_completion_func test_func,
+ nm_completion_func action_func,
+ ...);
+
+gboolean nm_completion_boolean_test(int tries, va_list args);
+gboolean nm_completion_boolean_function1_test(int tries, va_list args);
+gboolean nm_completion_boolean_function2_test(int tries, va_list args);
+#define nm_completion_boolean_function_test nm_completion_boolean_function1_test
+
#endif