diff options
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 |
commit | 2df9a5ddf6d004cf5f218bb807733db1741931bc (patch) | |
tree | d7cd224c20254cd10137bfb5df7a364b29277b1e | |
parent | 68bcb9cceb5d87c2776e91efb680f9441ac92aa0 (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-- | ChangeLog | 49 | ||||
-rw-r--r-- | configure.in | 4 | ||||
-rw-r--r-- | info-daemon/NetworkManagerInfoDbus.c | 5 | ||||
-rw-r--r-- | panel-applet/NMWirelessApplet.c | 8 | ||||
-rw-r--r-- | src/NetworkManager.c | 4 | ||||
-rw-r--r-- | src/NetworkManagerAP.c | 2 | ||||
-rw-r--r-- | src/NetworkManagerAP.h | 2 | ||||
-rw-r--r-- | src/NetworkManagerDevice.c | 485 | ||||
-rw-r--r-- | src/NetworkManagerPolicy.c | 24 | ||||
-rw-r--r-- | src/NetworkManagerUtils.c | 211 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 36 |
11 files changed, 684 insertions, 146 deletions
@@ -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(¤t, NULL); + + return (nm_timeval_cmp(¤t, 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 |