diff options
author | (no author) <(no author)> | 2005-06-18 04:47:23 +0000 |
---|---|---|
committer | (no author) <(no author)@4912f4e0-d625-0410-9fb7-b9a5a253dbdc> | 2005-06-18 04:47:23 +0000 |
commit | b450082c16a69ea94b205e36efc938fb3c5c0acf (patch) | |
tree | 31a638bff327c7d578078679798ba5d8f454e6b0 | |
parent | 68bcb9cceb5d87c2776e91efb680f9441ac92aa0 (diff) |
This commit was manufactured by cvs2svn to create tagSTABLE_0_3_5_RELEASE
'STABLE_0_3_5_RELEASE'.
git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/tags/STABLE_0_3_5_RELEASE@717 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
50 files changed, 3514 insertions, 2384 deletions
@@ -1,3 +1,313 @@ +2005-06-17 Dan Williams <dcbw@redhat.com> + + * Tag 0.3.5 release + +2005-06-17 Dan Williams <dcbw@redhat.com> + + * panel-applet/NMWirelessAppletDbus.c + - Alphabetize wireless networks in the applet menu + +2005-06-17 Dan Williams <dcbw@redhat.com> + + Backport Wireless Scan Methods from HEAD + +2005-06-17 Dan Williams <dcbw@redhat.com> + + Backport static IP DNS fixup patch from HEAD + +2005-06-17 Dan Williams <dcbw@redhat.com> + + Backport Robert Love's applet beautification patch from HEAD + +2005-05-16 Dan Williams <dcbw@redhat.com> + + * Remove unused variables + +2005-05-16 Dan Williams <dcbw@redhat.com> + + * dhcpcd/client.c + - (dhcp_handle_transaction): Fix condition that may have resulted + in incorrect return of RET_DHCP_SUCCESS when we really timed out. + +2005-05-05 Dan Williams <dcbw@redhat.com> + + * src/nm-dbus-nm.c: Fix misuse of a g_assert() (Colin Walters) + + Patch from Bill Moss: + * src/NetworkManagerDevice.c: + - (nm_device_set_up_down): Fix return value checking of ioctl() + * src/NetworkManagerPolicy.c: + - (nm_policy_allowed_ap_list_update): Improve handling of + non-ESSID broadcasting access points + * src/NetworkManagerAPList.c: + - (nm_ap_list_remove_duplicate_essids): + (nm_ap_list_merge_scanned_ap): + Improve handling of non-ESSID broadcasting access points + + Patch from Tom Parker: + * src/NetworkManagerDevice.c: + - Use g_thread_join() rather than spinning when shutting down + device worker threads + * src/NetworkMangaer.c: + - (nm_data_free): unref the signal handler GIOChannel + * src/NetworkManagerAPList.c + - (nm_ap_list_unref): don't leak the list object + + Patch from Peter Jones: + - Remove usage of varargs so that we work on PPC too + +2005-04-06 Dan Williams <dcbw@redhat.com> + + Add debug code for socket/file descriptor leaks. We register every socket + that we open (except for stuff in dhcpcd/) for tracking, and print out the + list of sockets that we forgot to close on shutdown. This also consolidates + about 4 places where we opened sockets into 1 function in NetworkManagerUtils.c + +2005-04-06 Dan Williams <dcbw@redhat.com> + + * src/NetworkManagerAPList.[ch] + - (nm_ap_list_remove_ap_by_essid): new function + + * src/NetworkManagerDevice.c + - (nm_device_wireless_force_use): remove access points from the ignore list + when the user forces them + +2005-04-06 Dan Williams <dcbw@redhat.com> + + * dhcpcd/dhcpcd.c + - (dhcp_interface_free): fix a file descriptor leak that may have + caused network drivers to not unload due to refcounts > 0 + +2005-04-04 Dan Williams <dcbw@redhat.com> + + * src/NetworkManagerDevice.c: + - (nm_completion_scan_has_results): restore pre-completion-patch behavior + of only erroring after the second consecutive scan times out. Also + don't exit when the card requires more time than we can give it, just + log the event and continue. + +2005-04-01 Dan Williams <dcbw@redhat.com> + + Perform scans during device activation, if needed. Both activation + and scans run in the same GMainContext. Therefore, if an access point + is not found by the time the device starts activation, it will not + be available until after activation. We now try to scan during + activation (in nm_wa_test) every 15s so that all available access + points are more likely to be found and available for the activation + procedure. + + Also change nm_wireless_link_state_handle() to only update the "best" + AP if we are not forcing a device and if we are not about to change + state. This attempts to work around a race when forcing a device, + where the forced AP would get cleared out too soon by the link state + checking timeout in the main thread, and the activation attempt with + that AP would fail. + +2005-04-01 Dan Williams <dcbw@redhat.com> + + * src/NetworkManagerAPList.c + - (nm_ap_list_print_members): print out MAC addresses in text for, + not as a hex number + +2005-04-01 Dan Williams <dcbw@redhat.com> + + * po/POTFILES.in + - Update with new translatables + +2005-03-31 Dan Williams <dcbw@redhat.com> + + Tighten up handling of wireless devices that don't support wireless + scanning (ie, Orinoco). Due to restructuring of code, these devices + hadn't been doing pseudo-scanning for a while either and would just + spin waiting for an access point. They are now manual devices where + the user must choose the access point from the menu every time. All + "allowed" access points are listed in the applet's menu regardless + of whether or not they can be seen by the card, since it can't scan + anyway. + + * src/NetworkManager.c + - (nm_wireless_link_state_handle): new function, but only update + the "best" ap for non-scanning devices when its not activating, + and when no device is being forced on the card + - (nm_link_state_monitor): split wireless link state handling out + into separate function + + * src/NetworkManagerDevice.c + - (nm_device_copy_allowed_to_dev_list): new function + - (nm_device_new): populate non-scanning cards' AP lists with + access points from the "allowed" list + - (nm_device_new): don't start a scanning timeout for devices that + can't scan + - (nm_device_activation_schedule_finish): new parameter, should be + the AP that failed to be connected to, pass it on to the + activation finish function in NetworkManagerPolicy.c + - (nm_device_activate_wireless): don't ever try to get a new AP + for non-scanning devices, just fail. The user must choose + a new access point manually. + - (nm_device_activate): grab the AP that failed connection and + pass it on + - (nm_device_update_best_ap): Clear the best AP if we don't have + a link to it, user must manually choose a new one + - (nm_device_do_pseudo_scan): remove function + - (nm_device_wireless_process_scan_results): remove bits for non- + scanning cards since they never get here + - (nm_device_wireless_scan): remove bits for non-scanning devices, + and fake the scan list for test devices a bit earlier + + * src/NetworkManagerPolicy.c + - (nm_policy_activation_finish): use the failed_ap that we get + passed rather than getting the best_ap from the card, which + may have changed since we were scheduled + - (nm_policy_allowed_ap_list_update): for non-scanning devices, + update their scan list directly from the allowed list when + we get updates to the allowed list from NetworkManagerInfo + + * src/NetworkManagerPolicy.h + - New member for failed access point in NMActivationResult + +2005-03-31 Dan Williams <dcbw@redhat.com> + + * src/NetworkManagerDevice.c + - (nm_device_wireless_scan): Fix leak of scan results in some + instances + +2005-03-29 Dan Williams <dcbw@redhat.com> + + * src/NetworkManagerDevice.c + - (nm_device_set_essid): Work around Orinoco cards which need + extra time after setting the ESSID + +2005-03-29 Dan Williams <dcbw@redhat.com> + + * src/NetworkManagerDevice.c + - Merge one more bit of Peter Jones' completion patch + +2005-03-29 Dan Williams <dcbw@redhat.com> + + * src/NetworkManagerDevice.c + - (nm_device_force_use): Fix possible segfault + +2005-03-29 Dan Williams <dcbw@redhat.com> + + * src/NetworkManagerDevice.c + - Use iw_get_ext() where we should rather than iw_set_ext() + +2005-03-29 Dan Williams <dcbw@redhat.com> + + * src/NetworkManagerDevice.c + - (nm_device_set_up_down): remove check for unsupported devices + that caused NM to not bring devices up when they were + added to the device list. + +2005-03-28 Dan Williams <dcbw@redhat.com> + + Driver Notification patch: notifies the user when their driver + sucks. Gives them the option to ignore further insertions + of the card that has the sucky driver. + + * NetworkManager.h + - Remove the SEMI_SUPPORTED member from the NMDriverSupportLevel + enum and replace it with NO_CARRIER_DETECT and + NO_WIRELESS_SCAN + + * panel-applet/NMWirelessApplet.[ch] + - Merge essid.glade -> wireless-applet.glade + - Implement the "Your driver sucks" notification dialog + + * panel-applet/NMWirelessAppletDbus.c + - Change stuff from getSupportsCarrierDetect->getDriverSupportLevel + - Grab hardware address for each device from NM too + - Check whether the driver for each device sucks or not whenever + a new device is noticed + + * panel-applet/NMWirelessAppletOtherNetworkDialog.c + - Deal with stuff being in wireless-applet.glade now rather than essid.glade + + * src/NetworkManager.c + - Fix a double-unref on device removal + + * src/NetworkManagerUtils.c + - Set appropriate driver support level on a device that doesn't + support scanning or carrier detection + + * src/nm-dbus-device.c + - New "getHWAddress" dbus method on devices + - getSupportsCarrierDetect -> getDriverSupportLevel + +2005-03-28 Dan Williams <dcbw@redhat.com> + + Merge sleep functionality from HEAD + + * panel-applet/NMWirelessApplet.c + - Applet now sticks around when there is no connection + - Hook up the "Stop/Start all wireless devices" function + + * src/NetworkManager.c + - Don't perform wireless link state updates when asleep or + when wireless devices are stopped + + * src/NetworkManagerDbus.c + - New "status" value: "asleep" + + * src/NetworkManagerDevice.c + - Don't do wireless scans when asleep + + * src/NetworkManagerPolicy.c + - When asleep, return no "best" device + + * src/nm-dbus-nm.c + - New sleep/wake dbus APIs + - Actually hook up the wireless enable stuff so that stopping + all wireless devices works + +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/NetworkManager.h b/NetworkManager.h index 992849f91f..10c19f412e 100644 --- a/NetworkManager.h +++ b/NetworkManager.h @@ -78,7 +78,8 @@ typedef enum NMEncKeyType typedef enum NMDriverSupportLevel { NM_DRIVER_UNSUPPORTED = 0, - NM_DRIVER_SEMI_SUPPORTED, + NM_DRIVER_NO_CARRIER_DETECT, + NM_DRIVER_NO_WIRELESS_SCAN, NM_DRIVER_FULLY_SUPPORTED } NMDriverSupportLevel; @@ -132,6 +133,19 @@ typedef enum NMDeviceAuthMethod /* * Info-daemon specific preference locations */ -#define NMI_GCONF_WIRELESS_NETWORKS_PATH "/system/networking/wireless/networks" +#define NMI_GCONF_WIRELESS_NETWORKS_PATH "/system/networking/wireless/networks" +#define NMI_GCONF_WIRELESS_PATH "/system/networking/wireless" + +/* + * Wireless scanning methods + * + */ +typedef enum NMWirelessScanMethod +{ + NM_SCAN_METHOD_UNKNOWN = 0, + NM_SCAN_METHOD_ALWAYS, + NM_SCAN_METHOD_NEVER, + NM_SCAN_METHOD_WHEN_UNASSOCIATED +} NMWirelessScanMethod; #endif diff --git a/configure.in b/configure.in index f64b7c44f5..ca76908aec 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.5, 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/dhcpcd/client.c b/dhcpcd/client.c index 2c55b3a980..dbf796b630 100644 --- a/dhcpcd/client.c +++ b/dhcpcd/client.c @@ -492,8 +492,8 @@ int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_ char foobuf[512]; struct sockaddr_ll server_hw_addr; int data_good = 0; - int min_data_len = (sizeof (struct iphdr) + sizeof (struct udphdr)); - + int min_data_len = (sizeof (struct iphdr) + sizeof (struct udphdr)); + int int_err = RET_DHCP_TIMEOUT; if (iface->cease) goto out; @@ -513,11 +513,11 @@ int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_ memset (&addr, 0, sizeof (struct sockaddr)); memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); - err = sendto (iface->sk, udp_send, udp_send_len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof (struct sockaddr)); - if (iface->cease || ((err == -1) && (errno != EAGAIN))) + int_err = sendto (iface->sk, udp_send, udp_send_len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof (struct sockaddr)); + if (iface->cease || ((int_err == -1) && (errno != EAGAIN))) { #ifdef DEBUG - syslog (LOG_INFO, "DHCP: error sending, cease = %d, err = %d, errno = %d", iface->cease, err, errno); + syslog (LOG_INFO, "DHCP: error sending, cease = %d, err = %d, errno = %d", iface->cease, int_err, errno); #endif err = iface->cease ? RET_DHCP_CEASED : RET_DHCP_ERROR; goto out; @@ -530,7 +530,7 @@ int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_ err = RET_DHCP_TIMEOUT; goto out; } - } while ((err == -1) && (errno == EAGAIN)); + } while ((int_err == -1) && (errno == EAGAIN)); /* Set up the future time at which point to stop waiting for data * on our socket and try the request again. If that future point is @@ -559,9 +559,9 @@ int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_ char ethPacket[ETH_FRAME_LEN]; /* Wait for some kind of data to appear on the socket */ - if ((err = peekfd (iface, recv_sk, min_data_len, &recv_end)) != RET_DHCP_SUCCESS) + if ((int_err = peekfd (iface, recv_sk, min_data_len, &recv_end)) != RET_DHCP_SUCCESS) { - if (err == RET_DHCP_TIMEOUT) + if (int_err == RET_DHCP_TIMEOUT) break; goto out; } diff --git a/dhcpcd/dhcpcd.c b/dhcpcd/dhcpcd.c index e56c2da38c..ecf4b7677a 100644 --- a/dhcpcd/dhcpcd.c +++ b/dhcpcd/dhcpcd.c @@ -245,6 +245,8 @@ void dhcp_interface_free (dhcp_interface *iface) if (iface->foo_sk >= 0) close (iface->foo_sk); + if (iface->sk) + close (iface->sk); free (iface->iface); free (iface->client_options); free (iface); diff --git a/info-daemon/NetworkManagerInfo.c b/info-daemon/NetworkManagerInfo.c index 02666bfa4e..f214a021fd 100644 --- a/info-daemon/NetworkManagerInfo.c +++ b/info-daemon/NetworkManagerInfo.c @@ -47,13 +47,45 @@ static void nmi_spawn_notification_icon (NMIAppInfo *info); + +/* + * nmi_gconf_get_wireless_scan_method + * + * Grab the wireless scan method from GConf + * + */ +NMWirelessScanMethod nmi_gconf_get_wireless_scan_method (NMIAppInfo *info) +{ + NMWirelessScanMethod method = NM_SCAN_METHOD_ALWAYS; + GConfEntry * entry; + + g_return_val_if_fail (info, NM_SCAN_METHOD_ALWAYS); + g_return_val_if_fail (info->gconf_client, NM_SCAN_METHOD_ALWAYS); + + if ((entry = gconf_client_get_entry (info->gconf_client, NMI_GCONF_WIRELESS_PATH "/scan_method", NULL, TRUE, NULL))) + { + GConfValue * value = gconf_entry_get_value (entry); + + if (value && (value->type == GCONF_VALUE_INT)) + { + NMWirelessScanMethod temp_method = gconf_value_get_int (value); + + if ((method == NM_SCAN_METHOD_ALWAYS) || (method == NM_SCAN_METHOD_NEVER) || (method == NM_SCAN_METHOD_WHEN_UNASSOCIATED)) + method = temp_method; + } + } + + return method; +} + + /* - * nmi_gconf_notify_callback + * nmi_gconf_prefs_notify_callback * - * Callback from gconf when wireless networking key/values have changed. + * Callback from gconf when wireless key/values have changed. * */ -void nmi_gconf_notify_callback (GConfClient *client, guint connection_id, GConfEntry *entry, gpointer user_data) +void nmi_gconf_prefs_notify_callback (GConfClient *client, guint connection_id, GConfEntry *entry, gpointer user_data) { NMIAppInfo *info = (NMIAppInfo *)user_data; const char *key = NULL; @@ -64,11 +96,23 @@ void nmi_gconf_notify_callback (GConfClient *client, guint connection_id, GConfE if ((key = gconf_entry_get_key (entry))) { - int path_len = strlen (NMI_GCONF_WIRELESS_NETWORKS_PATH) + 1; + int net_path_len = strlen (NMI_GCONF_WIRELESS_PATH) + 1; + + if (strcmp (NMI_GCONF_WIRELESS_PATH "/scan_method", key) == 0) + { + GConfValue * value = gconf_entry_get_value (entry); - if (strncmp (NMI_GCONF_WIRELESS_NETWORKS_PATH"/", key, path_len) == 0) + if (value && (value->type == GCONF_VALUE_INT)) + { + NMWirelessScanMethod method = gconf_value_get_int (value); + + if ((method == NM_SCAN_METHOD_ALWAYS) || (method == NM_SCAN_METHOD_NEVER) || (method == NM_SCAN_METHOD_WHEN_UNASSOCIATED)) + nmi_dbus_signal_update_scan_method (info->connection); + } + } + if (strncmp (NMI_GCONF_WIRELESS_NETWORKS_PATH"/", key, net_path_len) == 0) { - char *network = g_strdup ((key + path_len)); + char *network = g_strdup ((key + net_path_len)); char *slash_pos; char *unescaped_network; @@ -178,7 +222,6 @@ int main( int argc, char *argv[] ) DBusConnection *dbus_connection; int err; NMIAppInfo *app_info = NULL; - GMainLoop *loop; guint notify_id; struct poptOption options[] = @@ -235,10 +278,9 @@ int main( int argc, char *argv[] ) * get change notifications for our wireless networking data. */ app_info->gconf_client = gconf_client_get_default (); - gconf_client_add_dir (app_info->gconf_client, NMI_GCONF_WIRELESS_NETWORKS_PATH, - GCONF_CLIENT_PRELOAD_NONE, NULL); - notify_id = gconf_client_notify_add (app_info->gconf_client, NMI_GCONF_WIRELESS_NETWORKS_PATH, - nmi_gconf_notify_callback, app_info, NULL, NULL); + gconf_client_add_dir (app_info->gconf_client, NMI_GCONF_WIRELESS_PATH, GCONF_CLIENT_PRELOAD_NONE, NULL); + notify_id = gconf_client_notify_add (app_info->gconf_client, NMI_GCONF_WIRELESS_PATH, + nmi_gconf_prefs_notify_callback, app_info, NULL, NULL); /* Create our own dbus service */ err = nmi_dbus_service_init (dbus_connection, app_info); diff --git a/info-daemon/NetworkManagerInfo.h b/info-daemon/NetworkManagerInfo.h index 4b1845a101..2c51636557 100644 --- a/info-daemon/NetworkManagerInfo.h +++ b/info-daemon/NetworkManagerInfo.h @@ -31,6 +31,7 @@ #include <dbus/dbus.h> #include <dbus/dbus-glib.h> #include <gconf/gconf-client.h> +#include "NetworkManager.h" struct NMIAppInfo { @@ -58,4 +59,6 @@ struct NMIAppInfo }; typedef struct NMIAppInfo NMIAppInfo; +NMWirelessScanMethod nmi_gconf_get_wireless_scan_method (NMIAppInfo *info); + #endif diff --git a/info-daemon/NetworkManagerInfoDbus.c b/info-daemon/NetworkManagerInfoDbus.c index 1cd5123754..fc12adc6cf 100644 --- a/info-daemon/NetworkManagerInfoDbus.c +++ b/info-daemon/NetworkManagerInfoDbus.c @@ -222,6 +222,55 @@ void nmi_dbus_return_vpn_password (DBusConnection *connection, DBusMessage *mess } /* + * nmi_dbus_signal_update_scan_method + * + * Signal NetworkManager that it needs to update its wireless scanning method + * + */ +void nmi_dbus_signal_update_scan_method (DBusConnection *connection) +{ + DBusMessage *message; + + g_return_if_fail (connection != NULL); + + message = dbus_message_new_signal (NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "WirelessScanMethodUpdate"); + if (!message) + { + syslog (LOG_WARNING, "nmi_dbus_signal_update_scan_method(): Not enough memory for new dbus message!"); + return; + } + + if (!dbus_connection_send (connection, message, NULL)) + syslog (LOG_WARNING, "nmi_dbus_signal_update_scan_method(): Could not raise the 'WirelessScanMethodUpdate' signal!"); + + dbus_message_unref (message); +} + + +/* + * nmi_dbus_get_wireless_scan_method + * + * Tell NetworkManager what wireless scanning method it should use + * + */ +static DBusMessage *nmi_dbus_get_wireless_scan_method (NMIAppInfo *info, DBusMessage *message) +{ + DBusMessage * reply = NULL; + NMWirelessScanMethod method = NM_SCAN_METHOD_ALWAYS; + GConfEntry * entry; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + method = nmi_gconf_get_wireless_scan_method (info); + reply = dbus_message_new_method_return (message); + dbus_message_append_args (reply, DBUS_TYPE_UINT32, &method, DBUS_TYPE_INVALID); + + return (reply); +} + + +/* * nmi_dbus_signal_update_network * * Signal NetworkManager that it needs to update info associated with a particular @@ -486,7 +535,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 +588,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); @@ -697,6 +749,8 @@ static DBusHandlerResult nmi_dbus_nmi_message_handler (DBusConnection *connectio gtk_widget_destroy (GTK_WIDGET (dialog)); } } + else if (strcmp ("getWirelessScanMethod", method) == 0) + reply_message = nmi_dbus_get_wireless_scan_method (info, message); else if (strcmp ("getNetworks", method) == 0) reply_message = nmi_dbus_get_networks (info, message); else if (strcmp ("getNetworkProperties", method) == 0) diff --git a/info-daemon/NetworkManagerInfoDbus.h b/info-daemon/NetworkManagerInfoDbus.h index 423ca44be9..d8918f70aa 100644 --- a/info-daemon/NetworkManagerInfoDbus.h +++ b/info-daemon/NetworkManagerInfoDbus.h @@ -41,6 +41,8 @@ void nmi_dbus_return_user_key (DBusConnection *connection, const char *devi void nmi_dbus_return_vpn_password (DBusConnection *connection, DBusMessage *message, const char *password); +void nmi_dbus_signal_update_scan_method (DBusConnection *connection); + void nmi_dbus_signal_update_network (DBusConnection *connection, const char *network, NMNetworkType type); #endif diff --git a/initscript/RedHat/Makefile.am b/initscript/RedHat/Makefile.am index 3ce9ed4a51..942b6f5eb9 100644 --- a/initscript/RedHat/Makefile.am +++ b/initscript/RedHat/Makefile.am @@ -1,4 +1,4 @@ -EXTRA_DIST = NetworkManager +EXTRA_DIST = NetworkManager nm-sleep.py nm-wake.py initddir = $(sysconfdir)/rc.d/init.d initd_SCRIPTS = NetworkManager diff --git a/initscript/RedHat/nm-sleep.py b/initscript/RedHat/nm-sleep.py new file mode 100755 index 0000000000..c8d89ac9ac --- /dev/null +++ b/initscript/RedHat/nm-sleep.py @@ -0,0 +1,10 @@ +#!/usr/bin/python + +import dbus +service = "org.freedesktop.NetworkManager" +object_path = "/org/freedesktop/NetworkManager" +interface = "org.freedesktop.NetworkManager" +bus = dbus.Bus (dbus.Bus.TYPE_SYSTEM) +NWM_service = bus.get_service (service) +nm = NWM_service.get_object (object_path, interface) +nm.sleep() diff --git a/initscript/RedHat/nm-wake.py b/initscript/RedHat/nm-wake.py new file mode 100755 index 0000000000..ef1059606f --- /dev/null +++ b/initscript/RedHat/nm-wake.py @@ -0,0 +1,10 @@ +#!/usr/bin/python + +import dbus +service = "org.freedesktop.NetworkManager" +object_path = "/org/freedesktop/NetworkManager" +interface = "org.freedesktop.NetworkManager" +bus = dbus.Bus (dbus.Bus.TYPE_SYSTEM) +NWM_service = bus.get_service (service) +nm = NWM_service.get_object (object_path, interface) +nm.wake() diff --git a/panel-applet/Makefile.am b/panel-applet/Makefile.am index f535a374c4..c3c066fdaf 100644 --- a/panel-applet/Makefile.am +++ b/panel-applet/Makefile.am @@ -8,7 +8,7 @@ INCLUDES = -I${top_srcdir} noinst_LTLIBRARIES = libnm_notification_applet.la gladedir = $(datadir)/NetworkManagerNotification -glade_DATA = essid.glade +glade_DATA = wireless-applet.glade libnm_notification_applet_la_CPPFLAGS = \ $(DBUS_CFLAGS) \ @@ -39,10 +39,6 @@ libnm_notification_applet_la_SOURCES = \ NMWirelessAppletOtherNetworkDialog.h \ menu-info.c \ menu-info.h \ - gtkcellview.c \ - gtkcellview.h \ - gtkcellrendererprogress.c \ - gtkcellrendererprogress.h \ $(NULL) libnm_notification_applet_la_SOURCES += \ diff --git a/panel-applet/NMWirelessApplet.c b/panel-applet/NMWirelessApplet.c index 90e6804d85..750a68d599 100644 --- a/panel-applet/NMWirelessApplet.c +++ b/panel-applet/NMWirelessApplet.c @@ -58,6 +58,7 @@ #include "menu-info.h" #define CFG_UPDATE_INTERVAL 1 +#define NMWA_GCONF_PATH "/apps/NetworkManagerNotification" /* Compat for GTK 2.4 and lower... */ #if (GTK_MAJOR_VERSION <= 2 && GTK_MINOR_VERSION < 6) @@ -121,10 +122,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 }; @@ -171,6 +178,279 @@ void nmwa_about_cb (NMWirelessApplet *applet) /* + * nmwa_gconf_get_wireless_scan_method + * + * Grab the wireless scan method from GConf + * + */ +NMWirelessScanMethod nmwa_gconf_get_wireless_scan_method (NMWirelessApplet *applet) +{ + NMWirelessScanMethod method = NM_SCAN_METHOD_ALWAYS; + GConfEntry * entry; + + g_return_val_if_fail (applet, NM_SCAN_METHOD_ALWAYS); + g_return_val_if_fail (applet->gconf_client, NM_SCAN_METHOD_ALWAYS); + + if ((entry = gconf_client_get_entry (applet->gconf_client, NMI_GCONF_WIRELESS_PATH "/scan_method", NULL, TRUE, NULL))) + { + GConfValue * value = gconf_entry_get_value (entry); + + if (value && (value->type == GCONF_VALUE_INT)) + { + NMWirelessScanMethod temp_method = gconf_value_get_int (value); + + if ((method == NM_SCAN_METHOD_ALWAYS) || (method == NM_SCAN_METHOD_NEVER) || (method == NM_SCAN_METHOD_WHEN_UNASSOCIATED)) + method = temp_method; + } + } + + return method; +} + + +/* + * nmwa_driver_notify_get_ignored_list + * + * Return list of devices for which we are supposed to ignore driver + * notifications for from GConf. + * + */ +GSList *nmwa_driver_notify_get_ignored_list (NMWirelessApplet *applet) +{ + char *key; + GConfValue *value; + GSList *mac_list = NULL; + + g_return_val_if_fail (applet != NULL, NULL); + g_return_val_if_fail (applet->gconf_client != NULL, NULL); + + /* Get current list of access point MAC addresses for this AP from GConf */ + key = g_strdup_printf ("%s/non_notify_cards", NMWA_GCONF_PATH); + value = gconf_client_get (applet->gconf_client, key, NULL); + + if (value && (value->type == GCONF_VALUE_LIST) && (gconf_value_get_list_type (value) == GCONF_VALUE_STRING)) + mac_list = gconf_client_get_list (applet->gconf_client, key, GCONF_VALUE_STRING, NULL); + + if (value) + gconf_value_free (value); + g_free (key); + + return (mac_list); +} + + +/* + * nmwa_driver_notify_is_device_ignored + * + * Look in GConf and determine whether or not we are supposed to + * ignore driver notifications for a particular device. + * + */ +gboolean nmwa_driver_notify_is_device_ignored (NMWirelessApplet *applet, NetworkDevice *dev) +{ + gboolean found = FALSE; + GSList *mac_list = NULL; + GSList *elt; + + g_return_val_if_fail (applet != NULL, TRUE); + g_return_val_if_fail (applet->gconf_client != NULL, TRUE); + g_return_val_if_fail (dev != NULL, TRUE); + g_return_val_if_fail (dev->addr != NULL, TRUE); + g_return_val_if_fail (strlen (dev->addr) > 0, TRUE); + + mac_list = nmwa_driver_notify_get_ignored_list (applet); + + /* Ensure that the MAC isn't already in the list */ + for (elt = mac_list; elt; elt = g_slist_next (elt)) + { + if (elt->data && !strcmp (dev->addr, elt->data)) + { + found = TRUE; + break; + } + } + + /* Free the list, since gconf_client_set_list deep-copies it */ + g_slist_foreach (mac_list, (GFunc)g_free, NULL); + g_slist_free (mac_list); + + return found; +} + + +/* + * nmwa_driver_notify_ignore_device + * + * Add a device's MAC address to the list of ones that we ignore + * in GConf. Stores user's pref for "Don't remind me". + * + */ +void nmwa_driver_notify_ignore_device (NMWirelessApplet *applet, NetworkDevice *dev) +{ + gboolean found = FALSE; + GSList *new_mac_list = NULL; + GSList *elt; + + g_return_if_fail (applet != NULL); + g_return_if_fail (applet->gconf_client != NULL); + g_return_if_fail (dev != NULL); + g_return_if_fail (dev->addr != NULL); + g_return_if_fail (strlen (dev->addr) > 0); + + new_mac_list = nmwa_driver_notify_get_ignored_list (applet); + + /* Ensure that the MAC isn't already in the list */ + for (elt = new_mac_list; elt; elt = g_slist_next (elt)) + { + if (elt->data && !strcmp (dev->addr, elt->data)) + { + found = TRUE; + break; + } + } + + /* Add the new MAC address to the end of the list */ + if (!found) + { + char *key = g_strdup_printf ("%s/non_notify_cards", NMWA_GCONF_PATH); + + new_mac_list = g_slist_append (new_mac_list, g_strdup (dev->addr)); + gconf_client_set_list (applet->gconf_client, key, GCONF_VALUE_STRING, new_mac_list, NULL); + g_free (key); + } + + /* Free the list, since gconf_client_set_list deep-copies it */ + g_slist_foreach (new_mac_list, (GFunc)g_free, NULL); + g_slist_free (new_mac_list); +} + +gboolean nmwa_driver_notify_dialog_delete_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + gtk_widget_destroy (widget); + return FALSE; +} + +gboolean nmwa_driver_notify_dialog_destroy_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + DriverNotifyCBData *cb_data = (DriverNotifyCBData *)(user_data); + NetworkDevice *dev; + + g_return_val_if_fail (cb_data != NULL, FALSE); + g_return_val_if_fail (cb_data->xml != NULL, FALSE); + + dev = cb_data->dev; + g_return_val_if_fail (dev != NULL, FALSE); + + network_device_unref (dev); + + g_object_unref (cb_data->xml); + g_free (cb_data); + + return FALSE; +} + + +gboolean nmwa_driver_notify_ok_cb (GtkButton *button, gpointer user_data) +{ + DriverNotifyCBData *cb_data = (DriverNotifyCBData *)(user_data); + NetworkDevice *dev; + NMWirelessApplet *applet; + GtkWidget *dialog; + GtkWidget *checkbox; + + g_return_val_if_fail (cb_data != NULL, FALSE); + g_return_val_if_fail (cb_data->xml != NULL, FALSE); + + dev = cb_data->dev; + g_return_val_if_fail (dev != NULL, FALSE); + + applet = cb_data->applet; + g_return_val_if_fail (applet != NULL, FALSE); + + checkbox = glade_xml_get_widget (cb_data->xml, "dont_remind_checkbox"); + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox))) + nmwa_driver_notify_ignore_device (applet, dev); + + dialog = glade_xml_get_widget (cb_data->xml, "driver_sucks_dialog"); + gtk_widget_destroy (dialog); + + return FALSE; +} + + +/* + * nmwa_driver_notify + * + * Notify the user if there's some problem with the driver + * of a specific network device. + * + */ +gboolean nmwa_driver_notify (gpointer user_data) +{ + DriverNotifyCBData *cb_data = (DriverNotifyCBData *)(user_data); + NetworkDevice *dev; + NMWirelessApplet *applet; + GtkDialog *dialog; + GtkLabel *label; + char *label_text = NULL; + GtkButton *button; + + g_return_val_if_fail (cb_data != NULL, FALSE); + + dev = cb_data->dev; + g_return_val_if_fail (dev != NULL, FALSE); + + applet = cb_data->applet; + g_return_val_if_fail (applet != NULL, FALSE); + g_return_val_if_fail (applet->glade_file != NULL, FALSE); + + /* If the user has already requested that we ignore notifications for + * this device, don't do anything. + */ + if (nmwa_driver_notify_is_device_ignored (applet, dev)) + return FALSE; + + cb_data->xml = glade_xml_new (applet->glade_file, "driver_sucks_dialog", NULL); + if (cb_data->xml == NULL) + { + show_warning_dialog (TRUE, _("The NetworkManager Applet could not find some required resources (the glade file was not found).")); + return FALSE; + } + + dialog = GTK_DIALOG (glade_xml_get_widget (cb_data->xml, "driver_sucks_dialog")); + g_signal_connect (G_OBJECT (dialog), "destroy-event", GTK_SIGNAL_FUNC (nmwa_driver_notify_dialog_destroy_cb), cb_data); + g_signal_connect (G_OBJECT (dialog), "delete-event", GTK_SIGNAL_FUNC (nmwa_driver_notify_dialog_delete_cb), cb_data); + + label = GTK_LABEL (glade_xml_get_widget (cb_data->xml, "driver_sucks_label")); + if (dev->driver_support_level == NM_DRIVER_NO_WIRELESS_SCAN) + { + char *temp = g_strdup_printf (_("The network device \"%s (%s)\" does not support wireless scanning."), + dev->hal_name, dev->nm_name); + + label_text = g_strdup_printf (gtk_label_get_label (label), temp); + g_free (temp); + } + if (dev->driver_support_level == NM_DRIVER_NO_CARRIER_DETECT) + { + char *temp = g_strdup_printf (_("The network device \"%s (%s)\" does not support link detection."), + dev->hal_name, dev->nm_name); + + label_text = g_strdup_printf (gtk_label_get_label (label), temp); + g_free (temp); + } + if (label_text) + gtk_label_set_markup (label, label_text); + + button = GTK_BUTTON (glade_xml_get_widget (cb_data->xml, "ok_button")); + g_signal_connect (G_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (nmwa_driver_notify_ok_cb), cb_data); + + gtk_widget_show_all (GTK_WIDGET (dialog)); + + return (FALSE); +} + + +/* * nmwa_update_network_state * * Update our state based on what NetworkManager's network state is @@ -375,7 +655,7 @@ nmwa_update_state (NMWirelessApplet *applet) switch (applet->applet_state) { case (APPLET_STATE_NO_CONNECTION): - show_applet = FALSE; + pixbuf = applet->no_connection_icon; tip = g_strdup (_("No network connection")); break; @@ -702,6 +982,50 @@ static void nmwa_menu_item_activate (GtkMenuItem *item, gpointer user_data) } +static void scanning_menu_update (GtkWidget *menu_item, GtkCheckMenuItem *active_item) +{ + g_return_if_fail (active_item != NULL); + + g_object_set_data (G_OBJECT (menu_item), "block-activate", GINT_TO_POINTER(1)); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), (GTK_CHECK_MENU_ITEM (menu_item) == active_item) ? TRUE : FALSE); + g_object_set_data (G_OBJECT (menu_item), "block-activate", GINT_TO_POINTER(0)); +} + + +/* + * nmwa_menu_scanning_item_activate + * + * Handle a request to change scanning behavior + * + */ +static void nmwa_menu_scanning_item_activate (GtkMenuItem *item, gpointer user_data) +{ + NMWirelessApplet * applet = (NMWirelessApplet *)user_data; + char * tag; + + g_return_if_fail (item != NULL); + g_return_if_fail (applet != NULL); + + if ((tag = g_object_get_data (G_OBJECT (item), "block-activate"))) + if (GPOINTER_TO_INT(tag) == 1) + return; + + if ((tag = g_object_get_data (G_OBJECT (item), "scan_method"))) + { + NMWirelessScanMethod method = GPOINTER_TO_UINT (tag); + + if ((method == NM_SCAN_METHOD_ALWAYS) || (method == NM_SCAN_METHOD_NEVER) || (method == NM_SCAN_METHOD_WHEN_UNASSOCIATED)) + gconf_client_set_int (applet->gconf_client, NMI_GCONF_WIRELESS_PATH "/scan_method", method, NULL); + } + + /* Check only this menu item */ + if (!applet->scanning_menu) + return; + + gtk_container_foreach (GTK_CONTAINER (applet->scanning_menu), (GtkCallback) scanning_menu_update, (gpointer) item); +} + + /* * nmwa_menu_add_separator_item * @@ -948,18 +1272,11 @@ static void nmwa_menu_add_devices (GtkWidget *menu, NMWirelessApplet *applet) } -static void nmwa_set_scanning_enabled_cb (GtkWidget *widget, NMWirelessApplet *applet) -{ - g_return_if_fail (applet != NULL); - - nmwa_dbus_enable_scanning (applet, !applet->scanning_enabled); -} - static void nmwa_set_wireless_enabled_cb (GtkWidget *widget, NMWirelessApplet *applet) { g_return_if_fail (applet != NULL); - nmwa_dbus_enable_scanning (applet, !applet->wireless_enabled); + nmwa_dbus_enable_wireless (applet, !applet->wireless_enabled); } @@ -1094,29 +1411,12 @@ static void nmwa_context_menu_update (NMWirelessApplet *applet) GtkWidget *image; g_return_if_fail (applet != NULL); - g_return_if_fail (applet->pause_scanning_item != NULL); g_return_if_fail (applet->stop_wireless_item != NULL); g_mutex_lock (applet->data_mutex); - gtk_widget_destroy (applet->pause_scanning_item); gtk_widget_destroy (applet->stop_wireless_item); - if (applet->scanning_enabled) - { - applet->pause_scanning_item = gtk_image_menu_item_new_with_label (_("Pause Wireless Scanning")); - image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_MENU); - } - else - { - applet->pause_scanning_item = gtk_image_menu_item_new_with_label (_("Resume Wireless Scanning")); - image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU); - } - g_signal_connect (G_OBJECT (applet->pause_scanning_item), "activate", G_CALLBACK (nmwa_set_scanning_enabled_cb), applet); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (applet->pause_scanning_item), image); - gtk_menu_shell_insert (GTK_MENU_SHELL (applet->context_menu), applet->pause_scanning_item, 0); - gtk_widget_show_all (applet->pause_scanning_item); - if (applet->wireless_enabled) { applet->stop_wireless_item = gtk_image_menu_item_new_with_label (_("Stop All Wireless Devices")); @@ -1130,7 +1430,6 @@ static void nmwa_context_menu_update (NMWirelessApplet *applet) g_signal_connect (G_OBJECT (applet->stop_wireless_item), "activate", G_CALLBACK (nmwa_set_wireless_enabled_cb), applet); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (applet->stop_wireless_item), image); gtk_menu_shell_insert (GTK_MENU_SHELL (applet->context_menu), applet->stop_wireless_item, 1); - gtk_widget_set_sensitive (GTK_WIDGET (applet->stop_wireless_item), FALSE); gtk_widget_show_all (applet->stop_wireless_item); g_mutex_unlock (applet->data_mutex); @@ -1148,26 +1447,49 @@ static GtkWidget *nmwa_context_menu_create (NMWirelessApplet *applet) GtkWidget *menu; GtkWidget *menu_item; GtkWidget *image; + GtkWidget *scanning_subitem; g_return_val_if_fail (applet != NULL, NULL); menu = gtk_menu_new (); - applet->pause_scanning_item = gtk_image_menu_item_new_with_label (_("Pause Wireless Scanning")); - g_signal_connect (G_OBJECT (applet->pause_scanning_item), "activate", G_CALLBACK (nmwa_set_scanning_enabled_cb), applet); - image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (applet->pause_scanning_item), image); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), applet->pause_scanning_item); - + /* Construct the wireless scanning submenu */ + applet->scan_method = nmwa_gconf_get_wireless_scan_method (applet); + applet->scanning_item = gtk_menu_item_new_with_label (_("Wireless Network Discovery")); + applet->scanning_menu = gtk_menu_new (); + + scanning_subitem = GTK_WIDGET (gtk_check_menu_item_new_with_label (_("Always Search"))); + g_object_set_data (G_OBJECT (scanning_subitem), "scan_method", GUINT_TO_POINTER (NM_SCAN_METHOD_ALWAYS)); + if (applet->scan_method == NM_SCAN_METHOD_ALWAYS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (scanning_subitem), TRUE); + g_signal_connect (G_OBJECT (scanning_subitem), "activate", G_CALLBACK (nmwa_menu_scanning_item_activate), applet); + gtk_menu_shell_append (GTK_MENU_SHELL (applet->scanning_menu), GTK_WIDGET (scanning_subitem)); + + scanning_subitem = GTK_WIDGET (gtk_check_menu_item_new_with_label (_("Seach Only When Disconnected"))); + g_object_set_data (G_OBJECT (scanning_subitem), "scan_method", GINT_TO_POINTER (NM_SCAN_METHOD_WHEN_UNASSOCIATED)); + if (applet->scan_method == NM_SCAN_METHOD_WHEN_UNASSOCIATED) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (scanning_subitem), TRUE); + g_signal_connect (G_OBJECT (scanning_subitem), "activate", G_CALLBACK (nmwa_menu_scanning_item_activate), applet); + gtk_menu_shell_append (GTK_MENU_SHELL (applet->scanning_menu), GTK_WIDGET (scanning_subitem)); + + scanning_subitem = GTK_WIDGET (gtk_check_menu_item_new_with_label (_("Never Search"))); + g_object_set_data (G_OBJECT (scanning_subitem), "scan_method", GINT_TO_POINTER (NM_SCAN_METHOD_NEVER)); + if (applet->scan_method == NM_SCAN_METHOD_NEVER) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (scanning_subitem), TRUE); + g_signal_connect (G_OBJECT (scanning_subitem), "activate", G_CALLBACK (nmwa_menu_scanning_item_activate), applet); + gtk_menu_shell_append (GTK_MENU_SHELL (applet->scanning_menu), GTK_WIDGET (scanning_subitem)); + + gtk_menu_item_set_submenu (GTK_MENU_ITEM (applet->scanning_item), applet->scanning_menu); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), applet->scanning_item); + + /* Stop All Wireless Devices item */ applet->stop_wireless_item = gtk_image_menu_item_new_with_label (_("Stop All Wireless Devices")); g_signal_connect (G_OBJECT (applet->stop_wireless_item), "activate", G_CALLBACK (nmwa_set_wireless_enabled_cb), applet); image = gtk_image_new_from_stock (GTK_STOCK_STOP, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (applet->stop_wireless_item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), applet->stop_wireless_item); - gtk_widget_set_sensitive (GTK_WIDGET (applet->stop_wireless_item), FALSE); - menu_item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + nmwa_menu_add_separator_item (menu); menu_item = gtk_image_menu_item_new_with_label (_("Help")); /* g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (nmwa_help_cb), applet); */ @@ -1270,6 +1592,14 @@ static void nmwa_setup_widgets (NMWirelessApplet *applet) applet->context_menu = nmwa_context_menu_create (applet); applet->encryption_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + applet->glade_file = g_build_filename (GLADEDIR, "wireless-applet.glade", NULL); + if (!applet->glade_file || !g_file_test (applet->glade_file, G_FILE_TEST_IS_REGULAR)) + { + show_warning_dialog (TRUE, _("The NetworkManager Applet could not find some required resources (the glade file was not found).")); + g_free (applet->glade_file); + applet->glade_file = NULL; + } } @@ -1303,6 +1633,8 @@ static void nmwa_destroy (NMWirelessApplet *applet, gpointer user_data) nmwa_free_gui_data_model (applet); nmwa_free_dbus_data_model (applet); + + g_free (applet->glade_file); } @@ -1330,6 +1662,8 @@ static GtkWidget * nmwa_get_instance (NMWirelessApplet *applet) applet->thread_context = NULL; applet->thread_loop = NULL; applet->thread_done = FALSE; + applet->scanning_menu = NULL; + applet->scanning_item = NULL; /* Start our dbus thread */ if (!(applet->data_mutex = g_mutex_new ())) @@ -1395,6 +1729,7 @@ nmwa_icons_free (NMWirelessApplet *applet) gint i; g_object_unref (applet->no_nm_icon); + g_object_unref (applet->no_connection_icon); g_object_unref (applet->wired_icon); g_object_unref (applet->adhoc_icon); for (i = 0; i < NUM_WIRED_CONNECTING_FRAMES; i++) @@ -1417,6 +1752,7 @@ nmwa_icons_load_from_disk (NMWirelessApplet *applet, GtkIconTheme *icon_theme) gint icon_size = 22; applet->no_nm_icon = gtk_icon_theme_load_icon (icon_theme, "nm-device-broken", icon_size, 0, NULL); + applet->no_connection_icon = gtk_icon_theme_load_icon (icon_theme, "nm-no-connection", icon_size, 0, NULL); applet->wired_icon = gtk_icon_theme_load_icon (icon_theme, "nm-device-wired", icon_size, 0, NULL); applet->adhoc_icon = gtk_icon_theme_load_icon (icon_theme, "nm-adhoc", icon_size, 0, NULL); applet->wired_connecting_icons[0] = gtk_icon_theme_load_icon (icon_theme, "nm-connecting01", icon_size, 0, NULL); diff --git a/panel-applet/NMWirelessApplet.h b/panel-applet/NMWirelessApplet.h index f039bb96e4..8447215a67 100644 --- a/panel-applet/NMWirelessApplet.h +++ b/panel-applet/NMWirelessApplet.h @@ -32,6 +32,8 @@ #else #include "eggtrayicon.h" #endif +#include <net/ethernet.h> +#include "NetworkManager.h" typedef enum { @@ -70,7 +72,8 @@ typedef struct char *nm_device; int type; gboolean link; - gboolean supports_carrier_detect; + guint32 driver_support_level; + char *addr; char *nm_name; char *hal_name; char *udi; @@ -78,8 +81,6 @@ typedef struct GSList *networks; } NetworkDevice; - - #ifdef BUILD_NOTIFICATION_ICON #define NM_TYPE_WIRELESS_APPLET (nmwa_get_type()) @@ -107,8 +108,10 @@ typedef struct DBusConnection *connection; GConfClient *gconf_client; - GladeXML *ui_resources; + char *glade_file; guint redraw_timeout_id; + + /* dbus thread stuff */ GThread *dbus_thread; GMainContext *thread_context; GMainLoop *thread_loop; @@ -118,7 +121,7 @@ typedef struct GMutex *data_mutex; AppletState applet_state; gboolean is_adhoc; - gboolean scanning_enabled; + NMWirelessScanMethod scan_method; gboolean wireless_enabled; GSList *gui_device_list; @@ -130,6 +133,7 @@ typedef struct char *dbus_nm_status; GdkPixbuf *no_nm_icon; + GdkPixbuf *no_connection_icon; GdkPixbuf *wired_icon; GdkPixbuf *adhoc_icon; #define NUM_WIRED_CONNECTING_FRAMES 11 @@ -157,16 +161,24 @@ typedef struct GtkTooltips *tooltips; GtkWidget *context_menu; - GtkWidget *pause_scanning_item; + GtkWidget *scanning_item; + GtkWidget *scanning_menu; GtkWidget *stop_wireless_item; } NMWirelessApplet; +typedef struct +{ + NMWirelessApplet *applet; + NetworkDevice *dev; + GladeXML *xml; +} DriverNotifyCBData; NetworkDevice *nmwa_get_device_for_nm_device (GSList *dev_list, const char *nm_dev); WirelessNetwork *nmwa_get_net_for_nm_net (NetworkDevice *dev, const char *net_path); WirelessNetwork *nmwa_get_net_by_essid (NetworkDevice *dev, const char *essid); NMWirelessApplet *nmwa_new (void); void show_warning_dialog (gboolean error, gchar *mesg, ...); +gboolean nmwa_driver_notify (gpointer user_data); #endif diff --git a/panel-applet/NMWirelessAppletDbus.c b/panel-applet/NMWirelessAppletDbus.c index 9ff1d56005..4e8879e80c 100644 --- a/panel-applet/NMWirelessAppletDbus.c +++ b/panel-applet/NMWirelessAppletDbus.c @@ -36,6 +36,24 @@ /* dbus doesn't define a DBUS_TYPE_STRING_ARRAY so we fake one here for consistency */ #define DBUS_TYPE_STRING_ARRAY ((int) '$') +/* + * nm_null_safe_strcmp + * + * Doesn't freaking segfault if s1/s2 are NULL + * + */ +int nm_null_safe_strcmp (const char *s1, const char *s2) +{ + if (!s1 && !s2) + return 0; + if (!s1 && s2) + return -1; + if (s1 && !s2) + return 1; + + return (strcmp (s1, s2)); +} + /* * nmwa_dbus_call_nm_method @@ -271,7 +289,7 @@ static gboolean nmwa_dbus_get_device_link_active (NMWirelessApplet *applet, char break; default: - break; + break; } return (link); @@ -279,17 +297,17 @@ static gboolean nmwa_dbus_get_device_link_active (NMWirelessApplet *applet, char /* - * nmwa_dbus_get_device_supports_carrier_detect + * nmwa_dbus_get_device_driver_support_level * * Returns whether or not the device supports carrier detection. * */ -static gboolean nmwa_dbus_get_device_supports_carrier_detect (NMWirelessApplet *applet, char *net_path) +static gboolean nmwa_dbus_get_device_driver_support_level (NMWirelessApplet *applet, char *net_path) { - gboolean supports_carrier_detect = FALSE; + guint32 driver_support_level = FALSE; - switch (nmwa_dbus_call_nm_method (applet->connection, net_path, "getSupportsCarrierDetect", - DBUS_TYPE_BOOLEAN, (void **)(&supports_carrier_detect), NULL)) + switch (nmwa_dbus_call_nm_method (applet->connection, net_path, "getDriverSupportLevel", + DBUS_TYPE_UINT32, (void **)(&driver_support_level), NULL)) { case (RETURN_NO_NM): applet->applet_state = APPLET_STATE_NO_NM; @@ -299,7 +317,31 @@ static gboolean nmwa_dbus_get_device_supports_carrier_detect (NMWirelessApplet * break; } - return (supports_carrier_detect); + return (driver_support_level); +} + + +/* + * nmwa_dbus_get_hw_addr + * + * Return the hardware address of a given device + * + */ +static char * nmwa_dbus_get_hw_addr (NMWirelessApplet *applet, char *dev_path) +{ + char *addr = NULL; + + switch (nmwa_dbus_call_nm_method (applet->connection, dev_path, "getHWAddress", DBUS_TYPE_STRING, (void **)(&addr), NULL)) + { + case (RETURN_NO_NM): + applet->applet_state = APPLET_STATE_NO_NM; + break; + + default: + break; + } + + return (addr); } @@ -451,26 +493,6 @@ static gboolean nmwa_dbus_get_network_encrypted (NMWirelessApplet *applet, char /* - * nmwa_dbus_get_scanning_enabled - */ -static gboolean nmwa_dbus_get_scanning_enabled (NMWirelessApplet *applet) -{ - gboolean enabled = FALSE; - - switch (nmwa_dbus_call_nm_method (applet->connection, NM_DBUS_PATH, "getScanningEnabled", DBUS_TYPE_BOOLEAN, (void **)(&enabled), NULL)) - { - case (RETURN_NO_NM): - applet->applet_state = APPLET_STATE_NO_NM; - break; - - default: - break; - } - - return (enabled); -} - -/* * nmwa_dbus_get_wireless_enabled */ static gboolean nmwa_dbus_get_wireless_enabled (NMWirelessApplet *applet) @@ -704,28 +726,6 @@ void nmwa_dbus_create_network (DBusConnection *connection, const NetworkDevice * /* - * nmwa_dbus_enable_scanning - * - * Tell NetworkManager to start/stop scanning. - * - */ -void nmwa_dbus_enable_scanning (NMWirelessApplet *applet, gboolean enabled) -{ - DBusMessage *message; - - g_return_if_fail (applet != NULL); - g_return_if_fail (applet->connection != NULL); - - if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "setScanningEnabled"))) - { - dbus_message_append_args (message, DBUS_TYPE_BOOLEAN, enabled, DBUS_TYPE_INVALID); - dbus_connection_send (applet->connection, message, NULL); - applet->scanning_enabled = nmwa_dbus_get_scanning_enabled (applet); - } -} - - -/* * nmwa_dbus_enable_wireless * * Tell NetworkManager to enabled or disable all wireless devices. @@ -914,6 +914,7 @@ void network_device_unref (NetworkDevice *dev) g_free (dev->nm_name); g_free (dev->udi); g_free (dev->hal_name); + g_free (dev->addr); g_free (dev); memset (dev, 0, sizeof (NetworkDevice)); } @@ -959,7 +960,8 @@ NetworkDevice *network_device_copy (NetworkDevice *src) dev->nm_device = g_strdup (src->nm_device); dev->type = src->type; dev->link = src->link; - dev->supports_carrier_detect = src->supports_carrier_detect; + dev->addr = g_strdup (src->addr); + dev->driver_support_level = src->driver_support_level; dev->nm_name = g_strdup (src->nm_name); dev->hal_name = g_strdup (src->hal_name); dev->udi = g_strdup (src->udi); @@ -996,6 +998,36 @@ void network_device_add_wireless_network (NetworkDevice *dev, WirelessNetwork *n } +static int sort_networks_function (WirelessNetwork *a, WirelessNetwork *b) +{ + const char *name_a = a->essid; + const char *name_b = b->essid; + + if (name_a && !name_b) + return -1; + else if (!name_a && name_b) + return 1; + else if (!name_a && !name_b) + return 0; + else + return strcasecmp (name_a, name_b); +} + +/* + * network_device_sort_wireless_networks + * + * Alphabetize the wireless networks list + * + */ +void network_device_sort_wireless_networks (NetworkDevice *dev) +{ + g_return_if_fail (dev != NULL); + g_return_if_fail (dev->type == DEVICE_TYPE_WIRELESS_ETHERNET); + + dev->networks = g_slist_sort (dev->networks, (GCompareFunc) sort_networks_function); +} + + /* * nmwa_dbus_get_one_wireless_network * @@ -1157,9 +1189,12 @@ void nmwa_copy_data_model (NMWirelessApplet *applet) for (elt = applet->dbus_device_list; elt; elt = g_slist_next (elt)) { NetworkDevice *src = (NetworkDevice *)(elt->data); - NetworkDevice *dst = network_device_copy (src); + NetworkDevice *dst = NULL; + + if (src->type == DEVICE_TYPE_WIRELESS_ETHERNET) + network_device_sort_wireless_networks (src); - if (dst) + if ((dst = network_device_copy (src))) { /* Transfer ownership of device to list, don't need to unref it */ applet->gui_device_list = g_slist_append (applet->gui_device_list, dst); @@ -1192,6 +1227,10 @@ static gboolean nmwa_dbus_update_active_device_strength (gpointer user_data) g_return_val_if_fail (user_data != NULL, FALSE); applet = (NMWirelessApplet *)user_data; + + if (applet->applet_state == APPLET_STATE_NO_NM) + return TRUE; + if (applet->gui_active_device && (applet->gui_active_device->type == DEVICE_TYPE_WIRELESS_ETHERNET)) { guint8 strength = nmwa_dbus_get_object_strength (applet, applet->gui_active_device->nm_device); @@ -1316,6 +1355,73 @@ static void nmwa_dbus_device_update_one_network (NMWirelessApplet *applet, DBusM /* + * nmwa_dbus_schedule_driver_notification + * + * Schedule the driver notification routine to run in the main loop. + * + */ +void nmwa_dbus_schedule_driver_notification (NMWirelessApplet *applet, NetworkDevice *dev) +{ + DriverNotifyCBData *cb_data; + + g_return_if_fail (applet != NULL); + g_return_if_fail (dev != NULL); + + cb_data = g_malloc0 (sizeof (DriverNotifyCBData)); + cb_data->applet = applet; + cb_data->dev = dev; + + g_idle_add (nmwa_driver_notify, (gpointer)cb_data); +} + + +/* + * nmwa_dbus_check_drivers + * + * If a device got added, we notify the user if the device's driver + * has any problems (no carrier detect, no wireless scanning, etc). + * + */ +void nmwa_dbus_check_drivers (NMWirelessApplet *applet) +{ + GSList *elt; + + g_return_if_fail (applet != NULL); + + /* For every device that's in the dbus data model but not in + * the gui data model, signal the user. + */ + for (elt = applet->dbus_device_list; elt; elt = g_slist_next (elt)) + { + NetworkDevice *dbus_dev = (NetworkDevice *)(elt->data); + GSList *elt2; + gboolean found = FALSE; + + for (elt2 = applet->gui_device_list; elt2; elt2 = g_slist_next (elt2)) + { + NetworkDevice *gui_dev = (NetworkDevice *)(elt2->data); + + if ( !nm_null_safe_strcmp (dbus_dev->nm_device, gui_dev->nm_device) + && !nm_null_safe_strcmp (dbus_dev->addr, gui_dev->addr) + && !nm_null_safe_strcmp (dbus_dev->udi, gui_dev->udi)) + { + found = TRUE; + break; + } + } + + if ( !found + && ( (dbus_dev->driver_support_level == NM_DRIVER_NO_CARRIER_DETECT) + || (dbus_dev->driver_support_level == NM_DRIVER_NO_WIRELESS_SCAN))) + { + network_device_ref (dbus_dev); + nmwa_dbus_schedule_driver_notification (applet, dbus_dev); + } + } +} + + +/* * sort_devices_function * * Sort the devices for display... Wired devices at the top. @@ -1414,8 +1520,8 @@ static void nmwa_dbus_update_devices (NMWirelessApplet *applet) { dev->nm_device = g_strdup (devices[i]); dev->type = nmwa_dbus_get_device_type (applet, devices[i], APPLET_STATE_NO_CONNECTION); - if (dev->type == DEVICE_TYPE_WIRED_ETHERNET) - dev->supports_carrier_detect = nmwa_dbus_get_device_supports_carrier_detect (applet, devices[i]); + dev->driver_support_level = nmwa_dbus_get_device_driver_support_level (applet, devices[i]); + dev->addr = nmwa_dbus_get_hw_addr (applet, devices[i]); dev->link = nmwa_dbus_get_device_link_active (applet, devices[i]); dev->nm_name = g_strdup (name); dev->udi = nmwa_dbus_get_device_udi (applet, devices[i]); @@ -1447,12 +1553,14 @@ static void nmwa_dbus_update_devices (NMWirelessApplet *applet) /* Sort the devices for display */ applet->dbus_device_list = g_slist_sort (applet->dbus_device_list, sort_devices_function); + /* Notify user of issues with certain cards/drivers */ + nmwa_dbus_check_drivers (applet); + /* Now copy the data over to the GUI side */ g_mutex_lock (applet->data_mutex); nmwa_copy_data_model (applet); applet->is_adhoc = adhoc; - applet->scanning_enabled = nmwa_dbus_get_scanning_enabled (applet); applet->wireless_enabled = nmwa_dbus_get_wireless_enabled (applet); g_mutex_unlock (applet->data_mutex); diff --git a/panel-applet/NMWirelessAppletOtherNetworkDialog.c b/panel-applet/NMWirelessAppletOtherNetworkDialog.c index a6ebea9ed9..3b440c57e7 100644 --- a/panel-applet/NMWirelessAppletOtherNetworkDialog.c +++ b/panel-applet/NMWirelessAppletOtherNetworkDialog.c @@ -215,6 +215,9 @@ static GtkDialog *nmwa_other_network_dialog_init (GladeXML *xml, NMWirelessApple /* Set up the dialog */ dialog = GTK_DIALOG (glade_xml_get_widget (xml, "custom_essid_dialog")); + if (!dialog) + return NULL; + essid_entry = glade_xml_get_widget (xml, "essid_entry"); button = glade_xml_get_widget (xml, "ok_button"); @@ -302,26 +305,17 @@ static GtkDialog *nmwa_other_network_dialog_init (GladeXML *xml, NMWirelessApple void nmwa_other_network_dialog_run (NMWirelessApplet *applet, gboolean create_network) { gchar *glade_file; - GtkDialog *dialog; - GladeXML *xml; - gint response; + GtkDialog *dialog; + gint response; NetworkDevice *def_dev = NULL; + GladeXML *xml; g_return_if_fail (applet != NULL); + g_return_if_fail (applet->glade_file != NULL); - glade_file = g_build_filename (GLADEDIR, "essid.glade", NULL); - - if (!glade_file || !g_file_test (glade_file, G_FILE_TEST_IS_REGULAR)) - { - show_warning_dialog (TRUE, _("The NetworkManager Applet could not find some required resources (the glade file was not found).")); - return; - } - - xml = glade_xml_new (glade_file, NULL, NULL); - g_free (glade_file); + xml = glade_xml_new (applet->glade_file, NULL, NULL); if (xml == NULL) { - /* Reuse the above string to make the translators less angry. */ show_warning_dialog (TRUE, _("The NetworkManager Applet could not find some required resources (the glade file was not found).")); return; } diff --git a/panel-applet/gtkcellrendererprogress.c b/panel-applet/gtkcellrendererprogress.c deleted file mode 100644 index 4933c23d4b..0000000000 --- a/panel-applet/gtkcellrendererprogress.c +++ /dev/null @@ -1,387 +0,0 @@ -/* gtkcellrendererprogress.c - * Copyright (C) 2002 Naba Kumar <kh_naba@users.sourceforge.net> - * heavily modified by Jörgen Scheibengruber <mfcn@gmx.de> - * heavily modified by Marco Pesenti Gritti <marco@gnome.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -/* - * Modified by the GTK+ Team and others 1997-2004. See the AUTHORS - * file for a list of people on the GTK+ Team. See the ChangeLog - * files for a list of changes. These files are distributed with - * GTK+ at ftp://ftp.gtk.org/pub/gtk/. - */ - -/* GtkCellRendererProgress is public in GTK 2.6, but not in GTK 2.4. - */ - -#include <gtk/gtkversion.h> - -#if (GTK_MAJOR_VERSION <= 2 && GTK_MINOR_VERSION < 6) - -#include <stdlib.h> - -#include "gtkcellrendererprogress.h" -#define _(x) (x) -#define P_(x) (x) -#define Q_(x) (x) -#define N_(x) (x) - -#define GTK_CELL_RENDERER_PROGRESS_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \ - GTK_TYPE_CELL_RENDERER_PROGRESS, \ - GtkCellRendererProgressPrivate)) - -enum -{ - PROP_0, - PROP_VALUE, - PROP_TEXT -}; - -struct _GtkCellRendererProgressPrivate -{ - gint value; - gchar *text; - gchar *label; - gint min_h; - gint min_w; -}; - -static void gtk_cell_renderer_progress_finalize (GObject *object); -static void gtk_cell_renderer_progress_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void gtk_cell_renderer_progress_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_cell_renderer_progress_set_value (GtkCellRendererProgress *cellprogress, - gint value); -static void gtk_cell_renderer_progress_set_text (GtkCellRendererProgress *cellprogress, - const gchar *text); -static void compute_dimensions (GtkCellRenderer *cell, - GtkWidget *widget, - const gchar *text, - gint *width, - gint *height); -static void gtk_cell_renderer_progress_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height); -static void gtk_cell_renderer_progress_render (GtkCellRenderer *cell, - GdkWindow *window, - GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - guint flags); - - -G_DEFINE_TYPE (GtkCellRendererProgress, gtk_cell_renderer_progress, GTK_TYPE_CELL_RENDERER); - -static void -gtk_cell_renderer_progress_class_init (GtkCellRendererProgressClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass); - - object_class->finalize = gtk_cell_renderer_progress_finalize; - object_class->get_property = gtk_cell_renderer_progress_get_property; - object_class->set_property = gtk_cell_renderer_progress_set_property; - - cell_class->get_size = gtk_cell_renderer_progress_get_size; - cell_class->render = gtk_cell_renderer_progress_render; - - /** - * GtkCellRendererProgress:value: - * - * The "value" property determines the percentage to which the - * progress bar will be "filled in". - * - * Since: 2.6 - **/ - g_object_class_install_property (object_class, - PROP_VALUE, - g_param_spec_int ("value", - P_("Value"), - P_("Value of the progress bar"), - 0, 100, 0, - G_PARAM_READWRITE)); - - /** - * GtkCellRendererProgress:text: - * - * The "text" property determines the label which will be drawn - * over the progress bar. Setting this property to %NULL causes the default - * label to be displayed. Setting this property to an empty string causes - * no label to be displayed. - * - * Since: 2.6 - **/ - g_object_class_install_property (object_class, - PROP_TEXT, - g_param_spec_string ("text", - P_("Text"), - P_("Text on the progress bar"), - NULL, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, - sizeof (GtkCellRendererProgressPrivate)); -} - -static void -gtk_cell_renderer_progress_init (GtkCellRendererProgress *cellprogress) -{ - cellprogress->priv = GTK_CELL_RENDERER_PROGRESS_GET_PRIVATE (cellprogress); - cellprogress->priv->value = 0; - cellprogress->priv->text = NULL; - cellprogress->priv->label = NULL; - cellprogress->priv->min_w = -1; - cellprogress->priv->min_h = -1; -} - - -/** - * gtk_cell_renderer_progress_new: - * - * Creates a new #GtkCellRendererProgress. - * - * Return value: the new cell renderer - * - * Since: 2.6 - **/ -GtkCellRenderer* -gtk_cell_renderer_progress_new (void) -{ - return GTK_CELL_RENDERER (g_object_new (GTK_TYPE_CELL_RENDERER_PROGRESS, NULL)); -} - -static void -gtk_cell_renderer_progress_finalize (GObject *object) -{ - GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object); - - g_free (cellprogress->priv->text); - g_free (cellprogress->priv->label); - - G_OBJECT_CLASS (gtk_cell_renderer_progress_parent_class)->finalize (object); -} - -static void -gtk_cell_renderer_progress_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object); - - switch (param_id) - { - case PROP_VALUE: - g_value_set_int (value, cellprogress->priv->value); - break; - case PROP_TEXT: - g_value_set_string (value, cellprogress->priv->text); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - } -} - -static void -gtk_cell_renderer_progress_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object); - - switch (param_id) - { - case PROP_VALUE: - gtk_cell_renderer_progress_set_value (cellprogress, - g_value_get_int (value)); - break; - case PROP_TEXT: - gtk_cell_renderer_progress_set_text (cellprogress, - g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - } -} - -static void -gtk_cell_renderer_progress_set_value (GtkCellRendererProgress *cellprogress, - gint value) -{ - gchar *text; - - cellprogress->priv->value = value; - - if (cellprogress->priv->text) - text = g_strdup (cellprogress->priv->text); - else - text = g_strdup_printf (Q_("progress bar label|%d %%"), - cellprogress->priv->value); - - g_free (cellprogress->priv->label); - cellprogress->priv->label = text; -} - -static void -gtk_cell_renderer_progress_set_text (GtkCellRendererProgress *cellprogress, - const gchar *text) -{ - gchar *new_text; - - new_text = g_strdup (text); - g_free (cellprogress->priv->text); - cellprogress->priv->text = new_text; - - /* Update the label */ - gtk_cell_renderer_progress_set_value (cellprogress, cellprogress->priv->value); -} - -static void -compute_dimensions (GtkCellRenderer *cell, - GtkWidget *widget, - const gchar *text, - gint *width, - gint *height) -{ - PangoRectangle logical_rect; - PangoLayout *layout; - - layout = gtk_widget_create_pango_layout (widget, text); - pango_layout_get_pixel_extents (layout, NULL, &logical_rect); - - if (width) - *width = logical_rect.width + cell->xpad * 2 + widget->style->xthickness * 2; - - if (height) - *height = logical_rect.height + cell->ypad * 2 + widget->style->ythickness * 2; - - g_object_unref (G_OBJECT (layout)); -} - -static void -gtk_cell_renderer_progress_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height) -{ - GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell); - gint w, h; - gchar *text; - - if (cellprogress->priv->min_w < 0) - { - text = g_strdup_printf (Q_("progress bar label|%d %%"), 100); - compute_dimensions (cell, widget, text, - &cellprogress->priv->min_w, - &cellprogress->priv->min_h); - g_free (text); - } - - compute_dimensions (cell, widget, cellprogress->priv->label, &w, &h); - - if (width) - *width = MAX (cellprogress->priv->min_w, w); - - if (height) - *height = MIN (cellprogress->priv->min_h, h); -} - -static void -gtk_cell_renderer_progress_render (GtkCellRenderer *cell, - GdkWindow *window, - GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - guint flags) -{ - GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell); - GdkGC *gc; - PangoLayout *layout; - PangoRectangle logical_rect; - gint x, y, w, h, perc_w, pos; - GdkRectangle clip; - gboolean is_rtl; - - is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; - - gc = gdk_gc_new (window); - - x = cell_area->x + cell->xpad; - y = cell_area->y + cell->ypad; - - w = cell_area->width - cell->xpad * 2; - h = cell_area->height - cell->ypad * 2; - - gdk_gc_set_rgb_fg_color (gc, &widget->style->fg[GTK_STATE_NORMAL]); - gdk_draw_rectangle (window, gc, TRUE, x, y, w, h); - - x += widget->style->xthickness; - y += widget->style->ythickness; - w -= widget->style->xthickness * 2; - h -= widget->style->ythickness * 2; - gdk_gc_set_rgb_fg_color (gc, &widget->style->bg[GTK_STATE_NORMAL]); - gdk_draw_rectangle (window, gc, TRUE, x, y, w, h); - - gdk_gc_set_rgb_fg_color (gc, &widget->style->bg[GTK_STATE_SELECTED]); - perc_w = w * MAX (0, cellprogress->priv->value) / 100; - gdk_draw_rectangle (window, gc, TRUE, is_rtl ? (x + w - perc_w) : x, y, perc_w, h); - - layout = gtk_widget_create_pango_layout (widget, cellprogress->priv->label); - pango_layout_get_pixel_extents (layout, NULL, &logical_rect); - - pos = (w - logical_rect.width)/2; - - clip.x = x; - clip.y = y; - clip.width = is_rtl ? w - perc_w : perc_w; - clip.height = h; - - gtk_paint_layout (widget->style, window, - is_rtl ? GTK_STATE_NORMAL : GTK_STATE_SELECTED, - FALSE, &clip, widget, "progressbar", - x + pos, y + (h - logical_rect.height)/2, - layout); - - clip.x = clip.x + clip.width; - clip.width = w - clip.width; - - gtk_paint_layout (widget->style, window, - is_rtl ? GTK_STATE_SELECTED : GTK_STATE_NORMAL, - FALSE, &clip, widget, "progressbar", - x + pos, y + (h - logical_rect.height)/2, - layout); - - g_object_unref (G_OBJECT (layout)); - g_object_unref (G_OBJECT (gc)); -} - -#endif /* GTK < 2.6 check */ diff --git a/panel-applet/gtkcellrendererprogress.h b/panel-applet/gtkcellrendererprogress.h deleted file mode 100644 index ff47332823..0000000000 --- a/panel-applet/gtkcellrendererprogress.h +++ /dev/null @@ -1,79 +0,0 @@ -/* gtkcellrendererprogress.h - * Copyright (C) 2002 Naba Kumar <kh_naba@users.sourceforge.net> - * modified by Jörgen Scheibengruber <mfcn@gmx.de> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -/* - * Modified by the GTK+ Team and others 1997-2004. See the AUTHORS - * file for a list of people on the GTK+ Team. See the ChangeLog - * files for a list of changes. These files are distributed with - * GTK+ at ftp://ftp.gtk.org/pub/gtk/. - */ - - -/* GtkCellRendererProgress is public in GTK 2.6, but not in GTK 2.4. - */ - -#include <gtk/gtkversion.h> - -#if (GTK_MAJOR_VERSION <= 2 && GTK_MINOR_VERSION < 6) - -#ifndef __GTK_CELL_RENDERER_PROGRESS_H__ -#define __GTK_CELL_RENDERER_PROGRESS_H__ - -#include <gtk/gtkcellrenderer.h> - -G_BEGIN_DECLS - -#define GTK_TYPE_CELL_RENDERER_PROGRESS (gtk_cell_renderer_progress_get_type ()) -#define GTK_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_RENDERER_PROGRESS, GtkCellRendererProgress)) -#define GTK_CELL_RENDERER_PROGRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CELL_RENDERER_PROGRESS, GtkCellRendererProgressClass)) -#define GTK_IS_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_RENDERER_PROGRESS)) -#define GTK_IS_CELL_RENDERER_PROGRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CELL_RENDERER_PROGRESS)) -#define GTK_CELL_RENDERER_PROGRESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CELL_RENDERER_PROGRESS, GtkCellRendererProgressClass)) - -typedef struct _GtkCellRendererProgress GtkCellRendererProgress; -typedef struct _GtkCellRendererProgressClass GtkCellRendererProgressClass; -typedef struct _GtkCellRendererProgressPrivate GtkCellRendererProgressPrivate; - -struct _GtkCellRendererProgress -{ - GtkCellRenderer parent_instance; - - /*< private >*/ - GtkCellRendererProgressPrivate *priv; -}; - -struct _GtkCellRendererProgressClass -{ - GtkCellRendererClass parent_class; - - /* Padding for future expansion */ - void (*_gtk_reserved1) (void); - void (*_gtk_reserved2) (void); - void (*_gtk_reserved3) (void); - void (*_gtk_reserved4) (void); -}; - -GType gtk_cell_renderer_progress_get_type (void); -GtkCellRenderer* gtk_cell_renderer_progress_new (void); - -G_END_DECLS - -#endif /* __GTK_CELL_RENDERER_PROGRESS_H__ */ - -#endif /* GTK < 2.6 check */ diff --git a/panel-applet/gtkcellview.c b/panel-applet/gtkcellview.c deleted file mode 100644 index 15920fb9af..0000000000 --- a/panel-applet/gtkcellview.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* gtkellview.c - * Copyright (C) 2002, 2003 Kristian Rietveld <kris@gtk.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* GtkCellView is public in GTK 2.6, but not in GTK 2.4. We can't include - * this private copy of GtkCellView when using GTK 2.6 due to link-time errors. - */ - -#include <gtk/gtkversion.h> - -#if (GTK_MAJOR_VERSION <= 2 && GTK_MINOR_VERSION < 6) - -#include "gtkcellview.h" -#include <gtk/gtksignal.h> -#include <gtk/gtkcelllayout.h> -#include <gtk/gtkcellrenderertext.h> -#include <gtk/gtkcellrendererpixbuf.h> -#include <gobject/gmarshal.h> -#define _(x) (x) -#define P_(x) (x) -#define Q_(x) (x) -#define N_(x) (x) - -typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo; -struct _GtkCellViewCellInfo -{ - GtkCellRenderer *cell; - - gint requested_width; - gint real_width; - guint expand : 1; - guint pack : 1; - - GSList *attributes; - - GtkCellLayoutDataFunc func; - gpointer func_data; - GDestroyNotify destroy; -}; - -struct _GtkCellViewPrivate -{ - GtkTreeModel *model; - GtkTreeRowReference *displayed_row; - GList *cell_list; - gint spacing; - - GdkColor background; - gboolean background_set; -}; - - -static void gtk_cell_view_class_init (GtkCellViewClass *klass); -static void gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface); -static void gtk_cell_view_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void gtk_cell_view_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_cell_view_init (GtkCellView *cellview); -static void gtk_cell_view_finalize (GObject *object); -static void gtk_cell_view_style_set (GtkWidget *widget, - GtkStyle *previous_style); -static void gtk_cell_view_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_cell_view_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static gboolean gtk_cell_view_expose (GtkWidget *widget, - GdkEventExpose *event); -static void gtk_cell_view_set_valuesv (GtkCellView *cellview, - GtkCellRenderer *renderer, - va_list args); -static GtkCellViewCellInfo *gtk_cell_view_get_cell_info (GtkCellView *cellview, - GtkCellRenderer *renderer); - - -static void gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, - GtkCellRenderer *renderer, - gboolean expand); -static void gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout, - GtkCellRenderer *renderer, - gboolean expand); -static void gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout, - GtkCellRenderer *renderer, - const gchar *attribute, - gint column); -static void gtk_cell_view_cell_layout_clear (GtkCellLayout *layout); -static void gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout, - GtkCellRenderer *renderer); -static void gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout, - GtkCellRenderer *cell, - GtkCellLayoutDataFunc func, - gpointer func_data, - GDestroyNotify destroy); -static void gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, - GtkCellRenderer *cell, - gint position); - - -#define GTK_CELL_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW, GtkCellViewPrivate)) - -enum -{ - PROP_0, - PROP_BACKGROUND, - PROP_BACKGROUND_GDK, - PROP_BACKGROUND_SET -}; - -static GtkObjectClass *parent_class = NULL; - - -GType -gtk_cell_view_get_type (void) -{ - static GType cell_view_type = 0; - - if (!cell_view_type) - { - static const GTypeInfo cell_view_info = - { - sizeof (GtkCellViewClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_cell_view_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkCellView), - 0, - (GInstanceInitFunc) gtk_cell_view_init - }; - - static const GInterfaceInfo cell_layout_info = - { - (GInterfaceInitFunc) gtk_cell_view_cell_layout_init, - NULL, - NULL - }; - - cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCellView", - &cell_view_info, 0); - - g_type_add_interface_static (cell_view_type, GTK_TYPE_CELL_LAYOUT, - &cell_layout_info); - } - - return cell_view_type; -} - -static void -gtk_cell_view_class_init (GtkCellViewClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->get_property = gtk_cell_view_get_property; - gobject_class->set_property = gtk_cell_view_set_property; - gobject_class->finalize = gtk_cell_view_finalize; - - widget_class->expose_event = gtk_cell_view_expose; - widget_class->size_allocate = gtk_cell_view_size_allocate; - widget_class->size_request = gtk_cell_view_size_request; - widget_class->style_set = gtk_cell_view_style_set; - - /* properties */ - g_object_class_install_property (gobject_class, - PROP_BACKGROUND, - g_param_spec_string ("background", - P_("Background color name"), - P_("Background color as a string"), - NULL, - G_PARAM_WRITABLE)); - g_object_class_install_property (gobject_class, - PROP_BACKGROUND_GDK, - g_param_spec_boxed ("background_gdk", - P_("Background color"), - P_("Background color as a GdkColor"), - GDK_TYPE_COLOR, - G_PARAM_READABLE | G_PARAM_WRITABLE)); - -#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE)) - - ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET, - P_("Background set"), - P_("Whether this tag affects the background color")); - - g_type_class_add_private (gobject_class, sizeof (GtkCellViewPrivate)); -} - -static void -gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface) -{ - iface->pack_start = gtk_cell_view_cell_layout_pack_start; - iface->pack_end = gtk_cell_view_cell_layout_pack_end; - iface->clear = gtk_cell_view_cell_layout_clear; - iface->add_attribute = gtk_cell_view_cell_layout_add_attribute; - iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func; - iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes; - iface->reorder = gtk_cell_view_cell_layout_reorder; -} - -static void -gtk_cell_view_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GtkCellView *view = GTK_CELL_VIEW (object); - - switch (param_id) - { - case PROP_BACKGROUND_GDK: - { - GdkColor color; - - color = view->priv->background; - - g_value_set_boxed (value, &color); - } - break; - case PROP_BACKGROUND_SET: - g_value_set_boolean (value, view->priv->background_set); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -static void -gtk_cell_view_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkCellView *view = GTK_CELL_VIEW (object); - - switch (param_id) - { - case PROP_BACKGROUND: - { - GdkColor color; - - if (!g_value_get_string (value)) - gtk_cell_view_set_background_color (view, NULL); - else if (gdk_color_parse (g_value_get_string (value), &color)) - gtk_cell_view_set_background_color (view, &color); - else - g_warning ("Don't know color `%s'", g_value_get_string (value)); - - g_object_notify (object, "background_gdk"); - } - break; - case PROP_BACKGROUND_GDK: - gtk_cell_view_set_background_color (view, g_value_get_boxed (value)); - break; - case PROP_BACKGROUND_SET: - view->priv->background_set = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -static void -gtk_cell_view_init (GtkCellView *cellview) -{ - GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW); - - cellview->priv = GTK_CELL_VIEW_GET_PRIVATE (cellview); -} - -static void -gtk_cell_view_style_set (GtkWidget *widget, - GtkStyle *previous_style) -{ - if (previous_style && GTK_WIDGET_REALIZED (widget)) - gdk_window_set_background (widget->window, - &widget->style->base[GTK_WIDGET_STATE (widget)]); -} - -static void -gtk_cell_view_finalize (GObject *object) -{ - GtkCellView *cellview = GTK_CELL_VIEW (object); - - gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (cellview)); - - if (cellview->priv->model) - g_object_unref (cellview->priv->model); - - if (cellview->priv->displayed_row) - gtk_tree_row_reference_free (cellview->priv->displayed_row); - - (* G_OBJECT_CLASS (parent_class)->finalize) (object); -} - -static void -gtk_cell_view_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - GList *i; - gboolean first_cell = TRUE; - GtkCellView *cellview; - - cellview = GTK_CELL_VIEW (widget); - - requisition->width = 0; - requisition->height = 0; - - if (cellview->priv->displayed_row) - gtk_cell_view_set_cell_data (cellview); - - for (i = cellview->priv->cell_list; i; i = i->next) - { - gint width, height; - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (!info->cell->visible) - continue; - - if (!first_cell) - requisition->width += cellview->priv->spacing; - - gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL, - &width, &height); - - info->requested_width = width; - requisition->width += width; - requisition->height = MAX (requisition->height, height); - - first_cell = FALSE; - } -} - -static void -gtk_cell_view_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GList *i; - gint expand_cell_count = 0; - gint full_requested_width = 0; - gint extra_space; - GtkCellView *cellview; - - widget->allocation = *allocation; - - cellview = GTK_CELL_VIEW (widget); - - /* checking how much extra space we have */ - for (i = cellview->priv->cell_list; i; i = i->next) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (!info->cell->visible) - continue; - - if (info->expand) - expand_cell_count++; - - full_requested_width += info->requested_width; - } - - extra_space = widget->allocation.width - full_requested_width; - if (extra_space < 0) - extra_space = 0; - else if (extra_space > 0 && expand_cell_count > 0) - extra_space /= expand_cell_count; - - /* iterate list for PACK_START cells */ - for (i = cellview->priv->cell_list; i; i = i->next) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (info->pack == GTK_PACK_END) - continue; - - if (!info->cell->visible) - continue; - - info->real_width = info->requested_width + (info->expand?extra_space:0); - } - - /* iterate list for PACK_END cells */ - for (i = cellview->priv->cell_list; i; i = i->next) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (info->pack == GTK_PACK_START) - continue; - - if (!info->cell->visible) - continue; - - info->real_width = info->requested_width + (info->expand?extra_space:0); - } -} - -static gboolean -gtk_cell_view_expose (GtkWidget *widget, - GdkEventExpose *event) -{ - GList *i; - GtkCellView *cellview; - GdkRectangle area; - GtkCellRendererState state; - gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL); - - cellview = GTK_CELL_VIEW (widget); - - if (! GTK_WIDGET_DRAWABLE (widget)) - return FALSE; - - /* "blank" background */ - if (cellview->priv->background_set) - { - GdkGC *gc; - - gc = gdk_gc_new (GTK_WIDGET (cellview)->window); - gdk_gc_set_rgb_fg_color (gc, &cellview->priv->background); - - gdk_draw_rectangle (GTK_WIDGET (cellview)->window, - gc, - TRUE, - /*0, 0,*/ - widget->allocation.x, - widget->allocation.y, - - widget->allocation.width, - widget->allocation.height); - - g_object_unref (G_OBJECT (gc)); - } - - /* set cell data (if available) */ - if (cellview->priv->displayed_row) - gtk_cell_view_set_cell_data (cellview); - else if (cellview->priv->model) - return FALSE; - - /* render cells */ - area = widget->allocation; - - /* we draw on our very own window, initialize x and y to zero */ - area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0); - area.y = widget->allocation.y; - - if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) - state = GTK_CELL_RENDERER_PRELIT; - else - state = 0; - - /* PACK_START */ - for (i = cellview->priv->cell_list; i; i = i->next) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (info->pack == GTK_PACK_END) - continue; - - if (!info->cell->visible) - continue; - - area.width = info->real_width; - if (rtl) - area.x -= area.width; - - gtk_cell_renderer_render (info->cell, - event->window, - widget, - /* FIXME! */ - &area, &area, &event->area, state); - - if (!rtl) - area.x += info->real_width; - } - - area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width); - - /* PACK_END */ - for (i = cellview->priv->cell_list; i; i = i->next) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (info->pack == GTK_PACK_START) - continue; - - if (!info->cell->visible) - continue; - - area.width = info->real_width; - if (!rtl) - area.x -= area.width; - - gtk_cell_renderer_render (info->cell, - widget->window, - widget, - /* FIXME ! */ - &area, &area, &event->area, state); - if (rtl) - area.x += info->real_width; - } - - return FALSE; -} - -static GtkCellViewCellInfo * -gtk_cell_view_get_cell_info (GtkCellView *cellview, - GtkCellRenderer *renderer) -{ - GList *i; - - for (i = cellview->priv->cell_list; i; i = i->next) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (info->cell == renderer) - return info; - } - - return NULL; -} - -void -gtk_cell_view_set_cell_data (GtkCellView *cellview) -{ - GList *i; - GtkTreeIter iter; - GtkTreePath *path; - - g_return_if_fail (cellview->priv->displayed_row != NULL); - - path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row); - if (!path) - return; - - gtk_tree_model_get_iter (cellview->priv->model, &iter, path); - gtk_tree_path_free (path); - - for (i = cellview->priv->cell_list; i; i = i->next) - { - GSList *j; - GtkCellViewCellInfo *info = i->data; - - g_object_freeze_notify (G_OBJECT (info->cell)); - - for (j = info->attributes; j && j->next; j = j->next->next) - { - gchar *property = j->data; - gint column = GPOINTER_TO_INT (j->next->data); - GValue value = {0, }; - - gtk_tree_model_get_value (cellview->priv->model, &iter, - column, &value); - g_object_set_property (G_OBJECT (info->cell), - property, &value); - g_value_unset (&value); - } - - if (info->func) - (* info->func) (GTK_CELL_LAYOUT (cellview), - info->cell, - cellview->priv->model, - &iter, - info->func_data); - - g_object_thaw_notify (G_OBJECT (info->cell)); - } -} - -/* GtkCellLayout implementation */ -static void -gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, - GtkCellRenderer *renderer, - gboolean expand) -{ - GtkCellViewCellInfo *info; - GtkCellView *cellview = GTK_CELL_VIEW (layout); - - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer)); - - g_object_ref (G_OBJECT (renderer)); - gtk_object_sink (GTK_OBJECT (renderer)); - - info = g_new0 (GtkCellViewCellInfo, 1); - info->cell = renderer; - info->expand = expand ? TRUE : FALSE; - info->pack = GTK_PACK_START; - - cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); -} - -static void -gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout, - GtkCellRenderer *renderer, - gboolean expand) -{ - GtkCellViewCellInfo *info; - GtkCellView *cellview = GTK_CELL_VIEW (layout); - - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer)); - - g_object_ref (G_OBJECT (renderer)); - gtk_object_sink (GTK_OBJECT (renderer)); - - info = g_new0 (GtkCellViewCellInfo, 1); - info->cell = renderer; - info->expand = expand ? TRUE : FALSE; - info->pack = GTK_PACK_END; - - cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); -} - -static void -gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout, - GtkCellRenderer *renderer, - const gchar *attribute, - gint column) -{ - GtkCellViewCellInfo *info; - GtkCellView *cellview = GTK_CELL_VIEW (layout); - - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - info = gtk_cell_view_get_cell_info (cellview, renderer); - g_return_if_fail (info != NULL); - - info->attributes = g_slist_prepend (info->attributes, - GINT_TO_POINTER (column)); - info->attributes = g_slist_prepend (info->attributes, - g_strdup (attribute)); -} - -static void -gtk_cell_view_cell_layout_clear (GtkCellLayout *layout) -{ - GtkCellView *cellview = GTK_CELL_VIEW (layout); - - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - - while (cellview->priv->cell_list) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)cellview->priv->cell_list->data; - - gtk_cell_view_cell_layout_clear_attributes (layout, info->cell); - g_object_unref (G_OBJECT (info->cell)); - g_free (info); - cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, - cellview->priv->cell_list); - } -} - -static void -gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout, - GtkCellRenderer *cell, - GtkCellLayoutDataFunc func, - gpointer func_data, - GDestroyNotify destroy) -{ - GtkCellView *cellview = GTK_CELL_VIEW (layout); - GtkCellViewCellInfo *info; - - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - - info = gtk_cell_view_get_cell_info (cellview, cell); - g_return_if_fail (info != NULL); - - if (info->destroy) - { - GDestroyNotify d = info->destroy; - - info->destroy = NULL; - d (info->func_data); - } - - info->func = func; - info->func_data = func_data; - info->destroy = destroy; -} - -static void -gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout, - GtkCellRenderer *renderer) -{ - GtkCellViewCellInfo *info; - GtkCellView *cellview = GTK_CELL_VIEW (layout); - GSList *list; - - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - - info = gtk_cell_view_get_cell_info (cellview, renderer); - g_return_if_fail (info != NULL); - - list = info->attributes; - while (list && list->next) - { - g_free (list->data); - list = list->next->next; - } - - g_slist_free (info->attributes); - info->attributes = NULL; -} - -static void -gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, - GtkCellRenderer *cell, - gint position) -{ - GList *link; - GtkCellViewCellInfo *info; - GtkCellView *cellview = GTK_CELL_VIEW (layout); - - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); - - info = gtk_cell_view_get_cell_info (cellview, cell); - - g_return_if_fail (info != NULL); - g_return_if_fail (position >= 0); - - link = g_list_find (cellview->priv->cell_list, info); - - g_return_if_fail (link != NULL); - - cellview->priv->cell_list = g_list_remove_link (cellview->priv->cell_list, - link); - cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list, - info, position); - - gtk_widget_queue_draw (GTK_WIDGET (cellview)); -} - -/* public API */ -GtkWidget * -gtk_cell_view_new (void) -{ - GtkCellView *cellview; - - cellview = GTK_CELL_VIEW (g_object_new (gtk_cell_view_get_type (), NULL)); - - return GTK_WIDGET (cellview); -} - -GtkWidget * -gtk_cell_view_new_with_text (const gchar *text) -{ - GtkCellView *cellview; - GtkCellRenderer *renderer; - GValue value = {0, }; - - cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), - renderer, TRUE); - - g_value_init (&value, G_TYPE_STRING); - g_value_set_string (&value, text); - gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL); - g_value_unset (&value); - - return GTK_WIDGET (cellview); -} - -GtkWidget * -gtk_cell_view_new_with_markup (const gchar *markup) -{ - GtkCellView *cellview; - GtkCellRenderer *renderer; - GValue value = {0, }; - - cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), - renderer, TRUE); - - g_value_init (&value, G_TYPE_STRING); - g_value_set_string (&value, markup); - gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL); - g_value_unset (&value); - - return GTK_WIDGET (cellview); -} - -GtkWidget * -gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf) -{ - GtkCellView *cellview; - GtkCellRenderer *renderer; - GValue value = {0, }; - - cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); - - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), - renderer, TRUE); - - g_value_init (&value, GDK_TYPE_PIXBUF); - g_value_set_object (&value, pixbuf); - gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL); - g_value_unset (&value); - - return GTK_WIDGET (cellview); -} - -void -gtk_cell_view_set_value (GtkCellView *cell_view, - GtkCellRenderer *renderer, - gchar *property, - GValue *value) -{ - g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - - g_object_set_property (G_OBJECT (renderer), property, value); - - /* force resize and redraw */ - gtk_widget_queue_resize (GTK_WIDGET (cell_view)); - gtk_widget_queue_draw (GTK_WIDGET (cell_view)); -} - -static void -gtk_cell_view_set_valuesv (GtkCellView *cell_view, - GtkCellRenderer *renderer, - va_list args) -{ - gchar *attribute; - GValue *value; - - attribute = va_arg (args, gchar *); - - while (attribute) - { - value = va_arg (args, GValue *); - gtk_cell_view_set_value (cell_view, renderer, attribute, value); - attribute = va_arg (args, gchar *); - } -} - -void -gtk_cell_view_set_values (GtkCellView *cell_view, - GtkCellRenderer *renderer, - ...) -{ - va_list args; - - g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - g_return_if_fail (gtk_cell_view_get_cell_info (cell_view, renderer)); - - va_start (args, renderer); - gtk_cell_view_set_valuesv (cell_view, renderer, args); - va_end (args); -} - -void -gtk_cell_view_set_model (GtkCellView *cell_view, - GtkTreeModel *model) -{ - g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); - g_return_if_fail (GTK_IS_TREE_MODEL (model)); - - if (cell_view->priv->model) - { - if (cell_view->priv->displayed_row) - gtk_tree_row_reference_free (cell_view->priv->displayed_row); - cell_view->priv->displayed_row = NULL; - - g_object_unref (G_OBJECT (cell_view->priv->model)); - cell_view->priv->model = NULL; - } - - cell_view->priv->model = model; - - if (cell_view->priv->model) - g_object_ref (G_OBJECT (cell_view->priv->model)); -} - -/** - * gtk_cell_view_set_displayed_row: - * @cell_view: a #GtkCellView - * @path: a #GtkTreePath or %NULL to unset. - * - * Sets the row of the model that is currently displayed - * by the #GtkCellView. If the path is unset, then the - * contents of the cellview "stick" at their last value; - * this is not normally a desired result, but may be - * a needed intermediate state if say, the model for - * the #GtkCellView becomes temporarily empty. - **/ -void -gtk_cell_view_set_displayed_row (GtkCellView *cell_view, - GtkTreePath *path) -{ - g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); - g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model)); - - if (cell_view->priv->displayed_row) - gtk_tree_row_reference_free (cell_view->priv->displayed_row); - - if (path) - { - cell_view->priv->displayed_row = - gtk_tree_row_reference_new (cell_view->priv->model, path); - } - else - cell_view->priv->displayed_row = NULL; - - /* force resize and redraw */ - gtk_widget_queue_resize (GTK_WIDGET (cell_view)); - gtk_widget_queue_draw (GTK_WIDGET (cell_view)); -} - -GtkTreePath * -gtk_cell_view_get_displayed_row (GtkCellView *cell_view) -{ - g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL); - - if (!cell_view->priv->displayed_row) - return NULL; - - return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row); -} - -gboolean -gtk_cell_view_get_size_of_row (GtkCellView *cell_view, - GtkTreePath *path, - GtkRequisition *requisition) -{ - GtkTreeRowReference *tmp; - - g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE); - g_return_val_if_fail (path != NULL, FALSE); - g_return_val_if_fail (requisition != NULL, FALSE); - - tmp = cell_view->priv->displayed_row; - cell_view->priv->displayed_row = - gtk_tree_row_reference_new (cell_view->priv->model, path); - - gtk_cell_view_size_request (GTK_WIDGET (cell_view), requisition); - - gtk_tree_row_reference_free (cell_view->priv->displayed_row); - cell_view->priv->displayed_row = tmp; - - return TRUE; -} - -void -gtk_cell_view_set_background_color (GtkCellView *view, - const GdkColor *color) -{ - g_return_if_fail (GTK_IS_CELL_VIEW (view)); - - if (color) - { - if (!view->priv->background_set) - { - view->priv->background_set = TRUE; - g_object_notify (G_OBJECT (view), "background_set"); - } - - view->priv->background = *color; - } - else - { - if (view->priv->background_set) - { - view->priv->background_set = FALSE; - g_object_notify (G_OBJECT (view), "background_set"); - } - } -} - -GList * -gtk_cell_view_get_cell_renderers (GtkCellView *cell_view) -{ - GList *retval = NULL, *list; - - g_return_val_if_fail (cell_view != NULL, NULL); - - for (list = cell_view->priv->cell_list; list; list = list->next) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; - - retval = g_list_prepend (retval, info->cell); - } - - return g_list_reverse (retval); -} - -#endif /* GTK < 2.6 check */ diff --git a/panel-applet/gtkcellview.h b/panel-applet/gtkcellview.h deleted file mode 100644 index 6004013b77..0000000000 --- a/panel-applet/gtkcellview.h +++ /dev/null @@ -1,95 +0,0 @@ -/* gtkcellview.h - * Copyright (C) 2002, 2003 Kristian Rietveld <kris@gtk.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* GtkCellView is public in GTK 2.6, but not in GTK 2.4. We can't include - * this private copy of GtkCellView when using GTK 2.6 due to link-time errors. - */ - -#include <gtk/gtkversion.h> - -#if (GTK_MAJOR_VERSION <= 2 && GTK_MINOR_VERSION < 6) - -#ifndef __GTK_CELL_VIEW_H__ -#define __GTK_CELL_VIEW_H__ - -#include <gtk/gtkwidget.h> -#include <gtk/gtkcellrenderer.h> -#include <gtk/gtktreemodel.h> - -G_BEGIN_DECLS - -#define GTK_TYPE_CELL_VIEW (gtk_cell_view_get_type ()) -#define GTK_CELL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_VIEW, GtkCellView)) -#define GTK_CELL_VIEW_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_CELL_VIEW, GtkCellViewClass)) -#define GTK_IS_CELL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_VIEW)) -#define GTK_IS_CELL_VIEW_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_CELL_VIEW)) -#define GTK_CELL_VIEW_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GTK_TYPE_CELL_VIEW, GtkCellViewClass)) - -typedef struct _GtkCellView GtkCellView; -typedef struct _GtkCellViewClass GtkCellViewClass; -typedef struct _GtkCellViewPrivate GtkCellViewPrivate; - -struct _GtkCellView -{ - GtkWidget parent_instance; - - /*< private >*/ - GtkCellViewPrivate *priv; -}; - -struct _GtkCellViewClass -{ - GtkWidgetClass parent_class; -}; - -GType gtk_cell_view_get_type (void); -GtkWidget *gtk_cell_view_new (void); -GtkWidget *gtk_cell_view_new_with_text (const gchar *text); -GtkWidget *gtk_cell_view_new_with_markup (const gchar *markup); -GtkWidget *gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf); - - -void gtk_cell_view_set_value (GtkCellView *cell_view, - GtkCellRenderer *renderer, - gchar *property, - GValue *value); -void gtk_cell_view_set_values (GtkCellView *cell_view, - GtkCellRenderer *renderer, - ...); - -void gtk_cell_view_set_model (GtkCellView *cell_view, - GtkTreeModel *model); -void gtk_cell_view_set_displayed_row (GtkCellView *cell_view, - GtkTreePath *path); -GtkTreePath *gtk_cell_view_get_displayed_row (GtkCellView *cell_view); -gboolean gtk_cell_view_get_size_of_row (GtkCellView *cell_view, - GtkTreePath *path, - GtkRequisition *requisition); - -void gtk_cell_view_set_background_color (GtkCellView *cell_view, - const GdkColor *color); -void gtk_cell_view_set_cell_data (GtkCellView *cellview); -GList *gtk_cell_view_get_cell_renderers (GtkCellView *cellview); - -G_END_DECLS - -#endif /* __GTK_CELL_VIEW_H__ */ - - -#endif /* GTK < 2.6 check */ diff --git a/panel-applet/icons/Makefile.am b/panel-applet/icons/Makefile.am index 160e7b1fd8..5fddd90db7 100644 --- a/panel-applet/icons/Makefile.am +++ b/panel-applet/icons/Makefile.am @@ -7,6 +7,7 @@ largeicon_DATA=\ smallicondir=${datadir}/icons/hicolor/22x22/apps smallicon_DATA= \ + nm-no-connection.png\ nm-device-wired.png \ nm-adhoc.png \ nm-connecting01.png \ diff --git a/panel-applet/icons/nm-no-connection.png b/panel-applet/icons/nm-no-connection.png Binary files differnew file mode 100644 index 0000000000..f9cd02c4cb --- /dev/null +++ b/panel-applet/icons/nm-no-connection.png diff --git a/panel-applet/menu-info.c b/panel-applet/menu-info.c index 81229b1768..281bd3beeb 100644 --- a/panel-applet/menu-info.c +++ b/panel-applet/menu-info.c @@ -33,13 +33,8 @@ #include <stdio.h> #include <glib/gi18n.h> #include <string.h> -#include "menu-info.h" - -#if (GTK_MAJOR_VERSION <= 2 && GTK_MINOR_VERSION < 6) -#include "gtkcellview.h" -#include "gtkcellrendererprogress.h" -#endif +#include "menu-info.h" #include "NMWirelessAppletDbus.h" @@ -97,7 +92,7 @@ void wired_menu_item_update (NMWiredMenuItem *item, NetworkDevice *dev, const gi /* Only dim the item if the device supports carrier detection AND * we know it doesn't have a link. */ - if (dev->supports_carrier_detect == TRUE) + if (dev->driver_support_level != NM_DRIVER_NO_CARRIER_DETECT) gtk_widget_set_sensitive (GTK_WIDGET (item->check_item), dev->link); } @@ -180,9 +175,8 @@ struct NMNetworkMenuItem { GtkCheckMenuItem *check_item; GtkLabel *label; - GtkWidget *cell_view; + GtkWidget *progress; GtkWidget *security_image; - GObject *progress_bar; }; @@ -190,6 +184,11 @@ NMNetworkMenuItem *network_menu_item_new (GtkSizeGroup *encryption_size_group) { GtkWidget *hbox; NMNetworkMenuItem *item = g_malloc0 (sizeof (NMNetworkMenuItem)); + PangoFontDescription *fontdesc; + PangoFontMetrics *metrics; + PangoContext *context; + PangoLanguage *lang; + int ascent; g_return_val_if_fail (item != NULL, NULL); @@ -205,15 +204,25 @@ NMNetworkMenuItem *network_menu_item_new (GtkSizeGroup *encryption_size_group) gtk_container_add (GTK_CONTAINER (item->check_item), hbox); gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (item->label), TRUE, TRUE, 0); - item->cell_view = gtk_cell_view_new (); - item->progress_bar = g_object_new (GTK_TYPE_CELL_RENDERER_PROGRESS, "text", "", NULL); - gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (item->progress_bar), 150, -1); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (item->cell_view), GTK_CELL_RENDERER (item->progress_bar), TRUE); - gtk_box_pack_start (GTK_BOX (hbox), item->cell_view, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), item->security_image, FALSE, FALSE, 0); + item->progress = gtk_progress_bar_new (); + + /* get the font ascent for the current font and language */ + context = gtk_widget_get_pango_context (item->progress); + fontdesc = pango_context_get_font_description (context); + lang = pango_context_get_language (context); + metrics = pango_context_get_metrics (context, fontdesc, lang); + ascent = pango_font_metrics_get_ascent (metrics) * 1.5 / PANGO_SCALE; + pango_font_metrics_unref (metrics); + + /* size our progress bar to be five ascents long, one high */ + gtk_widget_set_size_request (item->progress, ascent * 5, -1); + + gtk_box_pack_end (GTK_BOX (hbox), item->progress, FALSE, TRUE, 0); + gtk_widget_show (GTK_WIDGET (item->label)); - gtk_widget_show (item->cell_view); + gtk_widget_show (item->progress); gtk_widget_show (hbox); return item; @@ -232,6 +241,7 @@ GtkCheckMenuItem *network_menu_item_get_check_item (NMNetworkMenuItem *item) void network_menu_item_update (NMNetworkMenuItem *item, WirelessNetwork *network, const gboolean is_encrypted) { char *display_essid; + gdouble percent; g_return_if_fail (item != NULL); g_return_if_fail (network != NULL); @@ -240,7 +250,8 @@ void network_menu_item_update (NMNetworkMenuItem *item, WirelessNetwork *network gtk_label_set_text (GTK_LABEL (item->label), display_essid); g_free (display_essid); - g_object_set (G_OBJECT (item->progress_bar), "value", CLAMP ((int) network->strength, 0, 100), NULL); + percent = (double) CLAMP (network->strength, 0, 100) / 100.0; + gtk_progress_set_percentage (GTK_PROGRESS (item->progress), percent); /* Deal with the encrypted icon */ g_object_set (item->security_image, "visible", is_encrypted, NULL); diff --git a/panel-applet/wireless-applet.glade b/panel-applet/wireless-applet.glade index 43dbdead39..f06f482048 100644 --- a/panel-applet/wireless-applet.glade +++ b/panel-applet/wireless-applet.glade @@ -153,4 +153,518 @@ You have chosen log in to the wireless network '%s'. If you are sure this wirel </child> </widget> +<widget class="GtkDialog" id="driver_sucks_dialog"> + <property name="border_width">6</property> + <property name="title" translatable="yes"> </property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ALWAYS</property> + <property name="modal">True</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_OK</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-warning</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkLabel" id="driver_sucks_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"><span weight="bold" size="larger">Reduced Network Functionality</span> + +%s It will not be completely functional.</property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="dont_remind_checkbox"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Don't remind me again</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="custom_essid_dialog"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="title" translatable="yes"></property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="default_width">488</property> + <property name="resizable">False</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">C_onnect</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-question</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkLabel" id="essid_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">12</property> + <property name="column_spacing">6</property> + + <child> + <widget class="GtkLabel" id="wireless_adapter_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Wireless _adapter:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">wireless_adapter_combo</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="wireless_adapter_combo"> + <property name="visible">True</property> + <property name="items" translatable="yes"></property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="label" translatable="yes">Wireless _network:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">essid_entry</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="essid_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">3</property> + <property name="bottom_padding">6</property> + <property name="left_padding">6</property> + <property name="right_padding">6</property> + + <child> + <widget class="GtkTable" id="table2"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">12</property> + <property name="column_spacing">6</property> + + <child> + <widget class="GtkLabel" id="key_type_combo_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Key type:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="passphrase_entry_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Passphrase:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="passphrase_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="key_type_combo"> + <property name="visible">True</property> + <property name="items" translatable="yes">128-bit passphrase (WEP) +Ascii key (WEP) +Hex key (WEP)</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkCheckButton" id="use_encryption_checkbox"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Connect with encryption enabled</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + </glade-interface> diff --git a/po/POTFILES.in b/po/POTFILES.in index eeb75de2f5..8aec20d7ae 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -9,3 +9,6 @@ panel-applet/NMWirelessAppletOtherNetworkDialog.c panel-applet/essid.glade panel-applet/menu-info.c examples/python/systray/eggtrayicon.c +panel-applet/NMWirelessApplet.xml +panel-applet/eggtrayicon.c +panel-applet/wireless-applet.glade diff --git a/src/Makefile.am b/src/Makefile.am index 2da17f00cd..47a311523b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,7 @@ NetworkManager_CPPFLAGS = \ -DG_DISABLE_DEPRECATED \ -DBINDIR=\"$(bindir)\" \ -DDATADIR=\"$(datadir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ -DARP_DEBUG if WITH_GCRYPT NetworkManager_CPPFLAGS += $(LIBGCRYPT_CFLAGS) diff --git a/src/NetworkManager.c b/src/NetworkManager.c index 558c19eb6d..5fc89e4dec 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -182,14 +182,13 @@ void nm_remove_device_from_list (NMData *data, const char *udi) nm_device_set_removed (dev, TRUE); nm_device_deactivate (dev, FALSE); nm_device_worker_thread_stop (dev); + nm_dbus_signal_device_status_change (data->dbus_connection, dev, DEVICE_LIST_CHANGE); nm_device_unref (dev); /* Remove the device entry from the device list and free its data */ data->dev_list = g_slist_remove_link (data->dev_list, elt); - nm_device_unref (elt->data); g_slist_free (elt); nm_policy_schedule_state_update (data); - nm_dbus_signal_device_status_change (data->dbus_connection, dev, DEVICE_LIST_CHANGE); break; } } @@ -413,6 +412,32 @@ void nm_schedule_status_signal_broadcast (NMData *data) } +void nm_wireless_link_state_handle (NMDevice *dev, NMData *data) +{ + g_return_if_fail (dev != NULL); + g_return_if_fail (data != NULL); + + if (!nm_device_get_link_active (dev)) + { + if ( nm_device_get_supports_wireless_scan (dev) + && !data->forcing_device + && data->state_modified_idle_id == 0) + { + nm_device_update_best_ap (dev); + } + else + { + /* If we loose a link to the access point, then + * look for another access point to connect to. + */ + if ( !nm_device_is_activating (dev) + && !data->forcing_device + && data->state_modified_idle_id == 0) + nm_device_update_best_ap (dev); + } + } +} + /* * nm_link_state_monitor * @@ -423,52 +448,52 @@ void nm_schedule_status_signal_broadcast (NMData *data) gboolean nm_link_state_monitor (gpointer user_data) { NMData *data = (NMData *)user_data; + GSList *elt; g_return_val_if_fail (data != NULL, TRUE); + if ((data->wireless_enabled == FALSE) || (data->asleep == TRUE)) + return (TRUE); + /* Attempt to acquire mutex for device list iteration. * If the acquire fails, just ignore the device deletion entirely. */ - if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__)) + if (!nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__)) { - GSList *elt; - for (elt = data->dev_list; elt; elt = g_slist_next (elt)) + syslog(LOG_ERR, "nm_link_state_monitor() could not acquire device list mutex."); + return TRUE; + } + + for (elt = data->dev_list; elt; elt = g_slist_next (elt)) + { + NMDevice *dev = (NMDevice *)(elt->data); + + if (dev) { - NMDevice *dev = (NMDevice *)(elt->data); + if (!nm_device_is_up (dev)) + nm_device_bring_up (dev); + nm_device_update_link_active (dev); - if (dev) + if (dev == data->active_device) { - if (!nm_device_is_up (dev)) - nm_device_bring_up (dev); - nm_device_update_link_active (dev); - - if (dev == data->active_device) - { - if (nm_device_is_wireless (dev) && !nm_device_get_link_active (dev)) - { - /* If we loose a link to the access point, then - * look for another access point to connect to. - */ - nm_device_update_best_ap (dev); - } - } - else - { - /* Ensure that the device has no IP address or routes. This will - * sometimes occur when a card gets inserted, and the system - * initscripts will run to bring the card up, but they get around to - * running _after_ we've been notified of insertion and cleared out - * card info already. - */ - nm_system_device_flush_routes (dev); - if (nm_device_get_ip4_address (dev) != 0) - nm_system_device_flush_addresses (dev); - } + if (nm_device_is_wireless (dev)) + nm_wireless_link_state_handle (dev, data); + } + else + { + /* Ensure that the device has no IP address or routes. This will + * sometimes occur when a card gets inserted, and the system + * initscripts will run to bring the card up, but they get around to + * running _after_ we've been notified of insertion and cleared out + * card info already. + */ + nm_system_device_flush_routes (dev); + if (nm_device_get_ip4_address (dev) != 0) + nm_system_device_flush_addresses (dev); } } - - nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); - } else syslog( LOG_ERR, "nm_link_state_monitor() could not acquire device list mutex." ); + } + nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); return (TRUE); } @@ -552,7 +577,7 @@ static NMData *nm_data_new (gboolean enable_test_devices) data->enable_test_devices = enable_test_devices; - data->scanning_enabled = TRUE; + data->scanning_method = NM_SCAN_METHOD_ALWAYS; data->wireless_enabled = TRUE; nm_policy_schedule_state_update (data); @@ -585,14 +610,18 @@ static void nm_data_free (NMData *data) g_main_loop_unref (data->main_loop); g_main_context_unref (data->main_context); + g_io_channel_unref(data->sigterm_iochannel); + memset (data, 0, sizeof (NMData)); } 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) @@ -730,7 +759,10 @@ int main( int argc, char *argv[] ) /* If NMI is running, grab allowed wireless network lists from it ASAP */ if (nm_dbus_is_info_daemon_running (nm_data->dbus_connection)) + { nm_policy_schedule_allowed_ap_list_update (nm_data); + nm_dbus_update_wireless_scan_method (nm_data->dbus_connection, nm_data); + } /* Right before we init hal, we have to make sure our mainloop integration function * knows about our GMainContext. HAL doesn't give us any way to pass that into its @@ -776,6 +808,8 @@ int main( int argc, char *argv[] ) /* Kill the watch functions */ g_source_remove (link_source_id); + nm_print_open_socks (); + /* Cleanup */ if (hal_shutdown (nm_data->hal_ctx) != 0) syslog (LOG_NOTICE, "Error: libhal shutdown failed"); 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/NetworkManagerAPList.c b/src/NetworkManagerAPList.c index f641eed6af..7c7c7d78c6 100644 --- a/src/NetworkManagerAPList.c +++ b/src/NetworkManagerAPList.c @@ -115,6 +115,7 @@ void nm_ap_list_unref (NMAccessPointList *list) nm_unlock_mutex (list->mutex, __FUNCTION__); g_mutex_free (list->mutex); + g_free(list); } } @@ -171,7 +172,7 @@ void nm_ap_list_remove_ap (NMAccessPointList *list, NMAccessPoint *ap) if (!nm_ap_list_lock (list)) { - syslog( LOG_ERR, "nm_ap_list_append_ap() could not acquire AP list mutex." ); + syslog( LOG_ERR, "nm_ap_list_remove_ap() could not acquire AP list mutex." ); return; } @@ -192,6 +193,115 @@ void nm_ap_list_remove_ap (NMAccessPointList *list, NMAccessPoint *ap) /* + * nm_ap_list_remove_ap_by_essid + * + * Helper to remove an AP from an AP list by the AP's ESSID. + * + */ +void nm_ap_list_remove_ap_by_essid (NMAccessPointList *list, const char *network) +{ + GSList *elt = NULL; + + g_return_if_fail (list != NULL); + g_return_if_fail (network != NULL); + + if (!nm_ap_list_lock (list)) + { + syslog (LOG_WARNING, "nm_ap_list_remove_ap_by_essid() could not acquire AP list mutex." ); + return; + } + + for (elt = list->ap_list; elt; elt = g_slist_next (elt)) + { + NMAccessPoint *list_ap = (NMAccessPoint *)(elt->data); + + if (nm_null_safe_strcmp (nm_ap_get_essid (list_ap), network) == 0) + { + list->ap_list = g_slist_remove_link (list->ap_list, elt); + nm_ap_unref (list_ap); + g_slist_free (elt); + break; + } + } + nm_ap_list_unlock (list); +} + +/* nm_ap_list_remove_duplicate_essids + * + */ +void nm_ap_list_remove_duplicate_essids (NMAccessPointList *list) +{ + NMAccessPoint *removal_ap; + NMAccessPoint *list_ap_max; + GSList *elt_i = NULL; + GSList *elt_j = NULL; + GSList *elt_max = NULL; + GSList *removal_list = NULL; + GSList *elt; + gint8 max_strength = 0; + gint8 strengthj = 0; + + g_return_if_fail (list != NULL); + + if (!nm_ap_list_lock (list)) + { + syslog (LOG_WARNING, "nm_ap_list_append_ap() could not acquire AP list mutex." ); + return; + } + + for (elt_i = list->ap_list; elt_i; elt_i = g_slist_next (elt_i)) + { + NMAccessPoint *list_ap_i = (NMAccessPoint *)(elt_i->data); + gboolean found = FALSE; + + for (elt_j = list->ap_list; elt_j < elt_i; elt_j = g_slist_next (elt_j)) + { + NMAccessPoint *list_ap_j = (NMAccessPoint *)(elt_j->data); + + if ((found = (nm_null_safe_strcmp (nm_ap_get_essid (list_ap_i), nm_ap_get_essid (list_ap_j)) == 0))) + break; + } + + if (found) + continue; + + elt_max = elt_i; + list_ap_max = (NMAccessPoint *)(elt_i->data); + max_strength = nm_ap_get_strength (list_ap_i); + + for (elt_j = g_slist_next (elt_i); elt_j; elt_j = g_slist_next (elt_j)) + { + NMAccessPoint *list_ap_j = (NMAccessPoint *)(elt_j->data); + + strengthj = nm_ap_get_strength (list_ap_j); + if (nm_null_safe_strcmp (nm_ap_get_essid (list_ap_i), nm_ap_get_essid (list_ap_j)) == 0) + { + if (strengthj > max_strength) + { + removal_list = g_slist_append (removal_list, list_ap_max); + list_ap_max = list_ap_j; + max_strength = strengthj; + } + else + removal_list = g_slist_append (removal_list, list_ap_j); + } + } + } + nm_ap_list_unlock (list); + + for (elt = removal_list; elt; elt = g_slist_next (elt)) + { + if ((removal_ap = (NMAccessPoint *)(elt->data))) + { + nm_ap_list_remove_ap (list, removal_ap); + } + } + g_slist_free (removal_list); + +} + + +/* * nm_ap_list_get_ap_by_essid * * Search through an access point list and return the access point @@ -380,49 +490,68 @@ void nm_ap_list_populate_from_nmi (NMAccessPointList *list, NMData *data) gboolean nm_ap_list_merge_scanned_ap (NMAccessPointList *list, NMAccessPoint *merge_ap, gboolean *new, gboolean *strength_changed) { - NMAccessPoint *list_ap; - gboolean success = FALSE; + NMAccessPoint *list_ap_addr, *list_ap_essid; g_return_val_if_fail (list != NULL, FALSE); g_return_val_if_fail (merge_ap != NULL, FALSE); g_return_val_if_fail (new != NULL, FALSE); g_return_val_if_fail (strength_changed != NULL, FALSE); - if (!(list_ap = nm_ap_list_get_ap_by_address (list, nm_ap_get_address (merge_ap)))) - list_ap = nm_ap_list_get_ap_by_essid (list, nm_ap_get_essid (merge_ap)); - - if (list_ap) + if ((list_ap_addr = nm_ap_list_get_ap_by_address (list, nm_ap_get_address (merge_ap)))) { - const GTimeVal *merge_ap_seen = nm_ap_get_last_seen (merge_ap); - const GTimeVal *list_ap_seen = nm_ap_get_last_seen (list_ap); - - /* Merge some properties on the AP that are new from scan to scan. */ - nm_ap_set_encrypted (list_ap, nm_ap_get_encrypted (merge_ap)); - nm_ap_set_auth_method (list_ap, nm_ap_get_auth_method (merge_ap)); - - /* Don't update the strength on the existing AP if the timestamp is - * the same as the AP we're going to merge (which means that they were - * found in the same scan, have the same ESSID, but are different APs) - * and the existing AP's strength is greater than the one we're about - * to merge. This helps keep the ESSID's reported strength that of the - * strongest AP we can see. - */ - if (!( (list_ap_seen->tv_sec == merge_ap_seen->tv_sec) - && (nm_ap_get_strength (list_ap) > nm_ap_get_strength (merge_ap)))) + + /* First, we check for an address match. If the merge AP has the + * same address as a list AP, the merge AP and the list AP + * must be the same physical AP. The list AP properties must be from + * a previous scan so the time_last_seen's are not equal. + * Update encryption, authentication method, + * strength, and the time_last_seen. */ + + const GTimeVal *merge_ap_seen = nm_ap_get_last_seen (merge_ap); + + nm_ap_set_encrypted (list_ap_addr, nm_ap_get_encrypted (merge_ap)); + nm_ap_set_auth_method (list_ap_addr, nm_ap_get_auth_method (merge_ap)); + if (nm_ap_get_strength (merge_ap) != nm_ap_get_strength (list_ap_addr)) { - nm_ap_set_strength (list_ap, nm_ap_get_strength (merge_ap)); + nm_ap_set_strength (list_ap_addr, nm_ap_get_strength (merge_ap)); *strength_changed = TRUE; } + nm_ap_set_last_seen (list_ap_addr, merge_ap_seen); + } + else if ((list_ap_essid = nm_ap_list_get_ap_by_essid (list, nm_ap_get_essid (merge_ap)))) + { - nm_ap_set_last_seen (list_ap, merge_ap_seen); + /* Second, we check for an ESSID match. In this case, + * a list AP has the same non-NULL ESSID as the merge AP. Update the + * encryption and authentication method. Update the strength and address + * except when the time_last_seen of the list AP is the same as the + * time_last_seen of the merge AP and the strength of the list AP is greater + * than or equal to the strength of the merge AP. If the time_last_seen's are + * equal, the merge AP and the list AP come from the same scan. + * Update the time_last_seen. */ + + const GTimeVal *merge_ap_seen = nm_ap_get_last_seen (merge_ap); + const GTimeVal *list_ap_essid_seen = nm_ap_get_last_seen (list_ap_essid); + + nm_ap_set_encrypted (list_ap_essid, nm_ap_get_encrypted (merge_ap)); + nm_ap_set_auth_method (list_ap_essid, nm_ap_get_auth_method (merge_ap)); + + if (!((list_ap_essid_seen->tv_sec == merge_ap_seen->tv_sec) + && (nm_ap_get_strength (list_ap_essid) >= nm_ap_get_strength (merge_ap)))) + { + nm_ap_set_strength (list_ap_essid, nm_ap_get_strength (merge_ap)); + nm_ap_set_address (list_ap_essid, nm_ap_get_address (merge_ap)); + *strength_changed = TRUE; + } + nm_ap_set_last_seen (list_ap_essid, merge_ap_seen); } else { - /* Add the whole AP, list takes ownership. */ + /* Add the merge AP to the list. */ + nm_ap_list_append_ap (list, merge_ap); *new = TRUE; } - return TRUE; } @@ -700,9 +829,16 @@ void nm_ap_list_print_members (NMAccessPointList *list, const char *name) while ((ap = nm_ap_list_iter_next (iter))) { const GTimeVal *timestamp = nm_ap_get_timestamp (ap); - syslog (LOG_ERR, "\t%d)\tobj=%p, essid='%s', timestamp=%ld, key='%s', enc=%d, addr=%p, strength=%d, %s=%f, rate=%d, inval=%d, mode=%d", + const struct ether_addr *addr; + char char_addr[20]; + + addr = nm_ap_get_address (ap); + memset (char_addr, 0, 20); + ether_ntoa_r (addr, &char_addr[0]); + + syslog (LOG_ERR, "\t%d)\tobj=%p, essid='%s', timestamp=%ld, key='%s', enc=%d, addr='%s', strength=%d, %s=%f, rate=%d, inval=%d, mode=%d", i, ap, nm_ap_get_essid (ap), timestamp->tv_sec, nm_ap_get_enc_key_source (ap), nm_ap_get_encrypted (ap), - nm_ap_get_address (ap), nm_ap_get_strength (ap), (nm_ap_get_freq (ap) < 20) ? "channel" : "freq", nm_ap_get_freq (ap), nm_ap_get_rate (ap), + char_addr, nm_ap_get_strength (ap), (nm_ap_get_freq (ap) < 20) ? "channel" : "freq", nm_ap_get_freq (ap), nm_ap_get_rate (ap), nm_ap_get_invalid (ap), nm_ap_get_mode (ap)); i++; } diff --git a/src/NetworkManagerAPList.h b/src/NetworkManagerAPList.h index 2a8add99c8..fa68275ca0 100644 --- a/src/NetworkManagerAPList.h +++ b/src/NetworkManagerAPList.h @@ -38,6 +38,8 @@ gboolean nm_ap_list_is_empty (NMAccessPointList *list); void nm_ap_list_append_ap (NMAccessPointList *list, NMAccessPoint *ap); void nm_ap_list_remove_ap (NMAccessPointList *list, NMAccessPoint *ap); +void nm_ap_list_remove_ap_by_essid (NMAccessPointList *list, const char *network); +void nm_ap_list_remove_duplicate_essids (NMAccessPointList *list); NMAccessPoint * nm_ap_list_get_ap_by_essid (NMAccessPointList *list, const char *network); NMAccessPoint * nm_ap_list_get_ap_by_address (NMAccessPointList *list, const struct ether_addr *addr); diff --git a/src/NetworkManagerDbus.c b/src/NetworkManagerDbus.c index 639086437c..fd58ae4ab8 100644 --- a/src/NetworkManagerDbus.c +++ b/src/NetworkManagerDbus.c @@ -325,6 +325,8 @@ char *nm_dbus_network_status_from_data (NMData *data) g_return_val_if_fail (data != NULL, NULL); + if (data->asleep == TRUE) + status = g_strdup ("asleep"); if (data->forcing_device) status = g_strdup ("scanning"); else if (data->active_device && nm_device_is_activating (data->active_device)) @@ -422,7 +424,6 @@ void nm_dbus_signal_wireless_network_change (DBusConnection *connection, NMDevic DBusMessage *message; char *dev_path; char *ap_path; - const char *signal; g_return_if_fail (connection != NULL); g_return_if_fail (dev != NULL); @@ -648,6 +649,44 @@ out: /* + * nm_dbus_update_wireless_scan_method + * + * Get the wireless scan method from NetworkManagerInfo + * + */ +void nm_dbus_update_wireless_scan_method (DBusConnection *connection, NMData *data) +{ + DBusMessage * message = NULL; + DBusMessage * reply = NULL; + + g_return_if_fail (connection != NULL); + g_return_if_fail (data != NULL); + + if (!(message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getWirelessScanMethod"))) + { + syslog (LOG_WARNING, "nm_dbus_update_wireless_scan_method(): Couldn't allocate the dbus message"); + return; + } + + if ((reply = dbus_connection_send_with_reply_and_block (connection, message, -1, NULL))) + { + NMWirelessScanMethod method; + + if (dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &method, DBUS_TYPE_INVALID)) + { + if ((method == NM_SCAN_METHOD_ALWAYS) || (method == NM_SCAN_METHOD_NEVER) || (method == NM_SCAN_METHOD_WHEN_UNASSOCIATED)) + data->scanning_method = method; + } + dbus_message_unref (reply); + } + else + syslog (LOG_WARNING, "nm_dbus_update_wireless_scan_method(): could not send dbus message"); + + dbus_message_unref (message); +} + + +/* * nm_dbus_update_network_auth_method * * Tell NetworkManagerInfo the updated auth_method of the AP @@ -841,19 +880,23 @@ static DBusHandlerResult nm_dbus_nmi_filter (DBusConnection *connection, DBusMes dbus_error_init (&error); - if ( (strcmp (object_path, NMI_DBUS_PATH) == 0) - && dbus_message_is_signal (message, NMI_DBUS_INTERFACE, "WirelessNetworkUpdate")) + if (strcmp (object_path, NMI_DBUS_PATH) == 0) { - char *network = NULL; - - if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &network, DBUS_TYPE_INVALID)) + if (dbus_message_is_signal (message, NMI_DBUS_INTERFACE, "WirelessNetworkUpdate")) { - /* Update a single wireless network's data */ - syslog (LOG_DEBUG, "NetworkManagerInfo triggered update of wireless network '%s'", network); - nm_ap_list_update_network_from_nmi (data->allowed_ap_list, network, data); - dbus_free (network); - handled = TRUE; + char * network = NULL; + + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &network, DBUS_TYPE_INVALID)) + { + /* Update a single wireless network's data */ + syslog (LOG_DEBUG, "NetworkManagerInfo triggered update of wireless network '%s'", network); + nm_ap_list_update_network_from_nmi (data->allowed_ap_list, network, data); + dbus_free (network); + handled = TRUE; + } } + else if (dbus_message_is_signal (message, NMI_DBUS_INTERFACE, "WirelessScanMethodUpdate")) + nm_dbus_update_wireless_scan_method (connection, data); } #if (DBUS_VERSION_MAJOR == 0 && DBUS_VERSION_MINOR == 22) else if (dbus_message_is_signal (message, DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, "ServiceCreated")) @@ -889,7 +932,10 @@ static DBusHandlerResult nm_dbus_nmi_filter (DBusConnection *connection, DBusMes * "ServiceCreated" signal in dbus <= 0.22 */ if (!old_owner_good && new_owner_good) + { nm_policy_schedule_allowed_ap_list_update (data); + nm_dbus_update_wireless_scan_method (connection, data); + } } } #else @@ -1051,7 +1097,6 @@ gboolean nm_dbus_is_info_daemon_running (DBusConnection *connection) DBusConnection *nm_dbus_init (NMData *data) { DBusError error; - dbus_bool_t success; DBusConnection *connection; DBusObjectPathVTable nm_vtable = {NULL, &nm_dbus_nm_message_handler, NULL, NULL, NULL, NULL}; DBusObjectPathVTable devices_vtable = {NULL, &nm_dbus_devices_message_handler, NULL, NULL, NULL, NULL}; diff --git a/src/NetworkManagerDbus.h b/src/NetworkManagerDbus.h index 9d7805b569..c7b27f9878 100644 --- a/src/NetworkManagerDbus.h +++ b/src/NetworkManagerDbus.h @@ -60,6 +60,8 @@ void nm_dbus_get_user_key_for_network (DBusConnection *connection, NMDevice * void nm_dbus_cancel_get_user_key_for_network (DBusConnection *connection); +void nm_dbus_update_wireless_scan_method (DBusConnection *connection, NMData *data); + NMAccessPoint *nm_dbus_get_network_object (DBusConnection *connection, NMNetworkType type, const char *network); gboolean nm_dbus_add_network_address (DBusConnection *connection, NMNetworkType type, const char *network, struct ether_addr *addr); diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index b3d6f2576d..a2f202f061 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 { @@ -53,6 +55,11 @@ typedef struct struct wireless_scan_head scan_head; } NMWirelessScanResults; +typedef struct +{ + NMDevice *dev; + gboolean reschedule; +} NMWirelessScanCB; /******************************************************/ @@ -67,10 +74,10 @@ typedef struct */ static gboolean nm_device_test_wireless_extensions (NMDevice *dev) { - int sk; - int err; - char ioctl_buf[64]; - + int err = -1; + char ioctl_buf[64]; + NMSock *sk; + g_return_val_if_fail (dev != NULL, FALSE); /* We obviously cannot probe test devices (since they don't @@ -80,11 +87,13 @@ static gboolean nm_device_test_wireless_extensions (NMDevice *dev) return (FALSE); ioctl_buf[63] = 0; - strncpy(ioctl_buf, nm_device_get_iface(dev), 63); + strncpy (ioctl_buf, nm_device_get_iface(dev), 63); - sk = iw_sockets_open (); - err = ioctl(sk, SIOCGIWNAME, ioctl_buf); - close (sk); + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) + { + err = ioctl (nm_dev_sock_get_fd (sk), SIOCGIWNAME, ioctl_buf); + nm_dev_sock_close (sk); + } return (err == 0); } @@ -97,24 +106,26 @@ static gboolean nm_device_test_wireless_extensions (NMDevice *dev) */ static gboolean nm_device_supports_wireless_scan (NMDevice *dev) { - int sk; - int err; - gboolean can_scan = TRUE; - wireless_scan_head scan_data; - + NMSock *sk; + int err; + gboolean can_scan = TRUE; + wireless_scan_head scan_data; + g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (dev->type == DEVICE_TYPE_WIRELESS_ETHERNET, FALSE); /* A test wireless device can always scan (we generate fake scan data for it) */ if (dev->test_device) return (TRUE); - - sk = iw_sockets_open (); - err = iw_scan (sk, (char *)nm_device_get_iface (dev), WIRELESS_EXT, &scan_data); - nm_dispose_scan_results (scan_data.result); - if ((err == -1) && (errno == EOPNOTSUPP)) - can_scan = FALSE; - close (sk); + + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) + { + err = iw_scan (nm_dev_sock_get_fd (sk), (char *)nm_device_get_iface (dev), WIRELESS_EXT, &scan_data); + nm_dispose_scan_results (scan_data.result); + if ((err == -1) && (errno == EOPNOTSUPP)) + can_scan = FALSE; + nm_dev_sock_close (sk); + } return (can_scan); } @@ -189,6 +200,50 @@ NMDevice *nm_get_device_by_iface (NMData *data, const char *iface) /* NMDevice object routines */ /*****************************************************************************/ + +/* + * nm_device_copy_allowed_to_dev_list + * + * For devices that don't support wireless scanning, copy + * the allowed AP list to the device's ap list. + * + */ +void nm_device_copy_allowed_to_dev_list (NMDevice *dev, NMAccessPointList *allowed_list) +{ + NMAPListIter *iter; + NMAccessPoint *src_ap; + NMAccessPointList *dev_list; + + g_return_if_fail (dev != NULL); + + if (allowed_list == NULL) + return; + + nm_device_ap_list_clear (dev); + dev->options.wireless.ap_list = nm_ap_list_new (NETWORK_TYPE_ALLOWED); + + if (!(iter = nm_ap_list_iter_new (allowed_list))) + return; + + dev_list = nm_device_ap_list_get (dev); + while ((src_ap = nm_ap_list_iter_next (iter))) + { + NMAccessPoint *dst_ap = nm_ap_new_from_ap (src_ap); + + /* Assume that if the allowed list AP has a saved encryption + * key that the AP is encrypted. + */ + if ( (nm_ap_get_auth_method (src_ap) == NM_DEVICE_AUTH_METHOD_OPEN_SYSTEM) + || (nm_ap_get_auth_method (src_ap) == NM_DEVICE_AUTH_METHOD_SHARED_KEY)) + nm_ap_set_encrypted (dst_ap, TRUE); + + nm_ap_list_append_ap (dev_list, dst_ap); + nm_ap_unref (dst_ap); + } + nm_ap_list_iter_free (iter); +} + + /* * nm_device_new * @@ -201,6 +256,8 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, { NMDevice *dev; GError *error = NULL; + char *msg; + nm_completion_args args; g_return_val_if_fail (iface != NULL, NULL); g_return_val_if_fail (strlen (iface) > 0, NULL); @@ -250,14 +307,12 @@ 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); - dev->driver_support_level = nm_get_driver_support_level (dev->app_data->hal_ctx, dev); + nm_device_bring_up_wait (dev, 0); /* Initialize wireless-specific options */ if (nm_device_is_wireless (dev)) { - int sk; + NMSock *sk; NMDeviceWirelessOptions *opts = &(dev->options.wireless); nm_device_set_mode (dev, NETWORK_MODE_INFRA); @@ -275,10 +330,16 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, opts->supports_wireless_scan = nm_device_supports_wireless_scan (dev); - if ((sk = iw_sockets_open ()) >= 0) + /* Non-scanning devices show the entire allowed AP list as their + * available networks. + */ + if (opts->supports_wireless_scan == FALSE) + nm_device_copy_allowed_to_dev_list (dev, app_data->allowed_ap_list); + + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { iwrange range; - if (iw_get_range_info (sk, nm_device_get_iface (dev), &range) >= 0) + if (iw_get_range_info (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), &range) >= 0) { int i; @@ -296,7 +357,7 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, for (i = 0; i < opts->num_freqs; i++) opts->freqs[i] = iw_freq2float (&(range.freq[i])); } - close (sk); + nm_dev_sock_close (sk); } } else if (nm_device_is_wired (dev)) @@ -305,6 +366,9 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, dev->options.wired.has_carrier_detect = TRUE; } + /* Must be called after carrier detect or wireless scan detect. */ + dev->driver_support_level = nm_get_driver_support_level (dev->app_data->hal_ctx, dev); + if (nm_device_get_driver_support_level (dev) != NM_DRIVER_UNSUPPORTED) { nm_device_update_link_active (dev); @@ -316,7 +380,8 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, nm_system_device_update_config_info (dev); } - if (!g_thread_create (nm_device_worker, dev, FALSE, &error)) + dev->worker = g_thread_create (nm_device_worker, dev, TRUE, &error); + if (!dev->worker) { syslog (LOG_CRIT, "nm_device_new (): could not create device worker thread. (glib said: '%s')", error->message); g_error_free (error); @@ -324,10 +389,15 @@ 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)); + args[0] = &dev->worker_started; + args[1] = msg; + args[2] = (void *)LOG_INFO; + args[3] = 0; + nm_wait_for_completion (NM_COMPLETION_TRIES_INFINITY, + G_USEC_PER_SEC / 20, nm_completion_boolean_test, NULL, args); + g_free (msg); + syslog (LOG_ERR, "%s: device's worker thread started, continuing.\n", nm_device_get_iface (dev)); return (dev); @@ -349,6 +419,7 @@ void nm_device_ref (NMDevice *dev) dev->refcount++; } + /* * nm_device_unref * @@ -367,10 +438,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,19 +487,23 @@ 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)) + /* Start the scanning timeout for devices that can do scanning */ + if (nm_device_is_wireless (dev) && nm_device_get_supports_wireless_scan (dev)) { - GSource *source = g_idle_source_new (); - guint source_id = 0; + GSource *source = g_idle_source_new (); + guint source_id = 0; + NMWirelessScanCB *scan_cb; + + scan_cb = g_malloc0 (sizeof (NMWirelessScanCB)); + scan_cb->dev = dev; + scan_cb->reschedule = TRUE; - g_source_set_callback (source, nm_device_wireless_scan, dev, NULL); + g_source_set_callback (source, nm_device_wireless_scan, scan_cb, NULL); source_id = g_source_attach (source, dev->context); g_source_unref (source); } + dev->worker_started = TRUE; g_main_loop_run (dev->loop); /* Remove any DHCP timeouts that might have been running */ @@ -443,7 +516,6 @@ static gpointer nm_device_worker (gpointer user_data) dev->loop = NULL; dev->context = NULL; - dev->worker_done = TRUE; nm_device_unref (dev); return NULL; @@ -454,9 +526,10 @@ 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); + g_thread_join(dev->worker); + dev->worker = NULL; } @@ -491,32 +564,6 @@ void nm_device_set_removed (NMDevice *dev, const gboolean removed) /* - * nm_device_open_sock - * - * Get a control socket for network operations. - * - */ -int nm_device_open_sock (void) -{ - int fd; - - /* Try to grab a control socket */ - fd = socket(PF_INET, SOCK_DGRAM, 0); - if (fd >= 0) - return (fd); - fd = socket(PF_PACKET, SOCK_DGRAM, 0); - if (fd >= 0) - return (fd); - fd = socket(PF_INET6, SOCK_DGRAM, 0); - if (fd >= 0) - return (fd); - - syslog (LOG_ERR, "nm_device_open_sock () could not get network control socket."); - return (-1); -} - - -/* * Return the amount of time we should wait for the device * to get a link, based on the # of frequencies it has to * scan. @@ -684,9 +731,9 @@ gboolean nm_device_get_supports_carrier_detect (NMDevice *dev) */ static gboolean nm_device_wireless_is_associated (NMDevice *dev) { - struct iwreq wrq; - int sk; - gboolean associated = FALSE; + struct iwreq wrq; + NMSock *sk; + gboolean associated = FALSE; g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (dev->app_data != NULL, FALSE); @@ -695,13 +742,13 @@ static gboolean nm_device_wireless_is_associated (NMDevice *dev) if (dev->test_device) return (nm_device_get_link_active (dev)); - if ((sk = iw_sockets_open ()) < 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL)) == NULL) return (FALSE); /* Some cards, for example ipw2x00 cards, can short-circuit the MAC * address check using this check on IWNAME. Its faster. */ - if (iw_get_ext (sk, nm_device_get_iface (dev), SIOCGIWNAME, &wrq) >= 0) + if (iw_get_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCGIWNAME, &wrq) >= 0) { if (!strcmp(wrq.u.name, "unassociated")) { @@ -718,13 +765,13 @@ static gboolean nm_device_wireless_is_associated (NMDevice *dev) * Is there a better way? Some cards don't work too well with this check, ie * Lucent WaveLAN. */ - if (iw_get_ext (sk, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0) + if (iw_get_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0) if (nm_ethernet_address_is_valid ((struct ether_addr *)(&(wrq.u.ap_addr.sa_data)))) associated = TRUE; } out: - close (sk); + nm_dev_sock_close (sk); return (associated); } @@ -850,8 +897,8 @@ void nm_device_update_link_active (NMDevice *dev) */ char * nm_device_get_essid (NMDevice *dev) { - int sk; - int err; + NMSock *sk; + int err; g_return_val_if_fail (dev != NULL, NULL); g_return_val_if_fail (nm_device_is_wireless (dev), NULL); @@ -873,12 +920,11 @@ char * nm_device_get_essid (NMDevice *dev) return (essid); } - sk = iw_sockets_open (); - if (sk >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { wireless_config info; - err = iw_get_basic_config(sk, nm_device_get_iface (dev), &info); + err = iw_get_basic_config (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), &info); if (err >= 0) { if (dev->options.wireless.cur_essid) @@ -888,7 +934,7 @@ char * nm_device_get_essid (NMDevice *dev) else syslog (LOG_ERR, "nm_device_get_essid(): error getting ESSID for device %s. errno = %d", nm_device_get_iface (dev), errno); - close (sk); + nm_dev_sock_close (sk); } return (dev->options.wireless.cur_essid); @@ -902,10 +948,10 @@ char * nm_device_get_essid (NMDevice *dev) */ void nm_device_set_essid (NMDevice *dev, const char *essid) { - int sk; - int err; - struct iwreq wreq; - unsigned char safe_essid[IW_ESSID_MAX_SIZE + 1] = "\0"; + NMSock *sk; + int err; + struct iwreq wreq; + unsigned char safe_essid[IW_ESSID_MAX_SIZE + 1] = "\0"; g_return_if_fail (dev != NULL); g_return_if_fail (nm_device_is_wireless (dev)); @@ -928,18 +974,24 @@ void nm_device_set_essid (NMDevice *dev, const char *essid) safe_essid[IW_ESSID_MAX_SIZE] = '\0'; } - sk = iw_sockets_open (); - if (sk >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { wreq.u.essid.pointer = (caddr_t) safe_essid; wreq.u.essid.length = strlen (safe_essid) + 1; wreq.u.essid.flags = 1; /* Enable essid on card */ - err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCSIWESSID, &wreq); + err = iw_set_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCSIWESSID, &wreq); if (err == -1) syslog (LOG_ERR, "nm_device_set_essid(): error setting ESSID '%s' for device %s. errno = %d", safe_essid, nm_device_get_iface (dev), errno); - close (sk); + nm_dev_sock_close (sk); + + /* Orinoco cards seem to need extra time here to not screw + * up the firmware, which reboots when you set the ESSID. + * Unfortunately, there's no way to know when the card is back up + * again. Sigh... + */ + sleep (2); } } @@ -952,9 +1004,9 @@ void nm_device_set_essid (NMDevice *dev, const char *essid) */ double nm_device_get_frequency (NMDevice *dev) { - int sk; - int err; - double freq = 0; + NMSock *sk; + int err; + double freq = 0; g_return_val_if_fail (dev != NULL, 0); g_return_val_if_fail (nm_device_is_wireless (dev), 0); @@ -963,18 +1015,17 @@ double nm_device_get_frequency (NMDevice *dev) if (dev->test_device) return 703000000; - sk = iw_sockets_open (); - if (sk >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { struct iwreq wrq; - err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCGIWFREQ, &wrq); + err = iw_get_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCGIWFREQ, &wrq); if (err >= 0) freq = iw_freq2float (&wrq.u.freq); if (err == -1) syslog (LOG_ERR, "nm_device_get_frequency(): error getting frequency for device %s. errno = %d", nm_device_get_iface (dev), errno); - close (sk); + nm_dev_sock_close (sk); } return (freq); } @@ -989,8 +1040,8 @@ double nm_device_get_frequency (NMDevice *dev) */ void nm_device_set_frequency (NMDevice *dev, const double freq) { - int sk; - int err; + NMSock *sk; + int err; /* HACK FOR NOW */ if (freq <= 0) @@ -1006,8 +1057,7 @@ void nm_device_set_frequency (NMDevice *dev, const double freq) if (nm_device_get_frequency (dev) == freq) return; - sk = iw_sockets_open (); - if (sk >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { struct iwreq wrq; @@ -1037,7 +1087,7 @@ void nm_device_set_frequency (NMDevice *dev, const double freq) wrq.u.freq.flags = IW_FREQ_FIXED; iw_float2freq (freq, &wrq.u.freq); } - err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCSIWFREQ, &wrq); + err = iw_set_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCSIWFREQ, &wrq); if (err == -1) { gboolean success = FALSE; @@ -1047,12 +1097,12 @@ void nm_device_set_frequency (NMDevice *dev, const double freq) wrq.u.freq.m = -1; wrq.u.freq.e = 0; wrq.u.freq.flags = 0; - if (iw_set_ext (sk, nm_device_get_iface (dev), SIOCSIWFREQ, &wrq) != -1) + if (iw_set_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCSIWFREQ, &wrq) != -1) success = TRUE; } } - close (sk); + nm_dev_sock_close (sk); } } @@ -1066,9 +1116,9 @@ void nm_device_set_frequency (NMDevice *dev, const double freq) */ int nm_device_get_bitrate (NMDevice *dev) { - int sk; - int err = -1; - struct iwreq wrq; + NMSock *sk; + int err = -1; + struct iwreq wrq; g_return_val_if_fail (dev != NULL, 0); g_return_val_if_fail (nm_device_is_wireless (dev), 0); @@ -1077,11 +1127,10 @@ int nm_device_get_bitrate (NMDevice *dev) if (dev->test_device) return 11; - sk = iw_sockets_open (); - if (sk >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { - err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCGIWRATE, &wrq); - close (sk); + err = iw_get_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCGIWRATE, &wrq); + nm_dev_sock_close (sk); } return ((err >= 0) ? wrq.u.bitrate.value / 1000 : 0); @@ -1097,7 +1146,7 @@ int nm_device_get_bitrate (NMDevice *dev) */ void nm_device_set_bitrate (NMDevice *dev, const int Mbps) { - int sk; + NMSock *sk; g_return_if_fail (dev != NULL); g_return_if_fail (nm_device_is_wireless (dev)); @@ -1109,8 +1158,7 @@ void nm_device_set_bitrate (NMDevice *dev, const int Mbps) if (nm_device_get_bitrate (dev) == Mbps) return; - sk = iw_sockets_open (); - if (sk >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { struct iwreq wrq; @@ -1126,9 +1174,9 @@ void nm_device_set_bitrate (NMDevice *dev, const int Mbps) wrq.u.bitrate.fixed = 0; } /* Silently fail as not all drivers support setting bitrate yet (ipw2x00 for example) */ - iw_set_ext (sk, nm_device_get_iface (dev), SIOCSIWRATE, &wrq); + iw_set_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCSIWRATE, &wrq); - close (sk); + nm_dev_sock_close (sk); } } @@ -1141,8 +1189,8 @@ void nm_device_set_bitrate (NMDevice *dev, const int Mbps) */ void nm_device_get_ap_address (NMDevice *dev, struct ether_addr *addr) { - int iwlib_socket; - struct iwreq wrq; + NMSock *sk; + struct iwreq wrq; g_return_if_fail (dev != NULL); g_return_if_fail (addr != NULL); @@ -1161,12 +1209,14 @@ void nm_device_get_ap_address (NMDevice *dev, struct ether_addr *addr) return; } - iwlib_socket = iw_sockets_open (); - if (iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0) - memcpy (addr, &(wrq.u.ap_addr.sa_data), sizeof (struct ether_addr)); - else - memset (addr, 0, sizeof (struct ether_addr)); - close (iwlib_socket); + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) + { + if (iw_get_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0) + memcpy (addr, &(wrq.u.ap_addr.sa_data), sizeof (struct ether_addr)); + else + memset (addr, 0, sizeof (struct ether_addr)); + nm_dev_sock_close (sk); + } } @@ -1181,8 +1231,7 @@ void nm_device_get_ap_address (NMDevice *dev, struct ether_addr *addr) */ void nm_device_set_enc_key (NMDevice *dev, const char *key, NMDeviceAuthMethod auth_method) { - int sk; - int err; + NMSock *sk; struct iwreq wreq; int keylen; unsigned char safe_key[IW_ENCODING_TOKEN_MAX + 1]; @@ -1204,8 +1253,7 @@ void nm_device_set_enc_key (NMDevice *dev, const char *key, NMDeviceAuthMethod a safe_key[IW_ENCODING_TOKEN_MAX] = '\0'; } - sk = iw_sockets_open (); - if (sk >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { wreq.u.data.pointer = (caddr_t) NULL; wreq.u.data.length = 0; @@ -1226,7 +1274,7 @@ void nm_device_set_enc_key (NMDevice *dev, const char *key, NMDeviceAuthMethod a { unsigned char parsed_key[IW_ENCODING_TOKEN_MAX + 1]; - keylen = iw_in_key_full (sk, nm_device_get_iface (dev), safe_key, &parsed_key[0], &wreq.u.data.flags); + keylen = iw_in_key_full (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), safe_key, &parsed_key[0], &wreq.u.data.flags); if (keylen > 0) { switch (auth_method) @@ -1249,12 +1297,11 @@ void nm_device_set_enc_key (NMDevice *dev, const char *key, NMDeviceAuthMethod a if (set_key) { - err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCSIWENCODE, &wreq); - if (err == -1) + if (iw_set_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCSIWENCODE, &wreq) == -1) syslog (LOG_ERR, "nm_device_set_enc_key(): error setting key for device %s. errno = %d", nm_device_get_iface (dev), errno); } - close (sk); + nm_dev_sock_close (sk); } else syslog (LOG_ERR, "nm_device_set_enc_key(): could not get wireless control socket."); } @@ -1288,8 +1335,8 @@ gint8 nm_device_get_signal_strength (NMDevice *dev) */ void nm_device_update_signal_strength (NMDevice *dev) { - gboolean has_range; - int sk; + gboolean has_range = FALSE; + NMSock *sk; iwrange range; iwstats stats; int percent = -1; @@ -1318,14 +1365,16 @@ void nm_device_update_signal_strength (NMDevice *dev) goto out; } - sk = iw_sockets_open (); - has_range = (iw_get_range_info (sk, nm_device_get_iface (dev), &range) >= 0); - if (iw_get_stats (sk, nm_device_get_iface (dev), &stats, &range, has_range) == 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { - percent = nm_wireless_qual_to_percent (&stats.qual, (const iwqual *)(&dev->options.wireless.max_qual), - (const iwqual *)(&dev->options.wireless.avg_qual)); + has_range = (iw_get_range_info (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), &range) >= 0); + if (iw_get_stats (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), &stats, &range, has_range) == 0) + { + percent = nm_wireless_qual_to_percent (&stats.qual, (const iwqual *)(&dev->options.wireless.max_qual), + (const iwqual *)(&dev->options.wireless.avg_qual)); + } + nm_dev_sock_close (sk); } - close (sk); /* Try to smooth out the strength. Atmel cards, for example, will give no strength * one second and normal strength the next. @@ -1359,7 +1408,7 @@ void nm_device_update_ip4_address (NMDevice *dev) { guint32 new_address; struct ifreq req; - int sk; + NMSock *sk; int err; g_return_if_fail (dev != NULL); @@ -1373,13 +1422,13 @@ void nm_device_update_ip4_address (NMDevice *dev) return; } - if ((sk = nm_device_open_sock ()) < 0) + if ((sk = nm_dev_sock_open (dev, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) return; memset (&req, 0, sizeof (struct ifreq)); strncpy ((char *)(&req.ifr_name), nm_device_get_iface (dev), strlen (nm_device_get_iface (dev))); - err = ioctl (sk, SIOCGIFADDR, &req); - close (sk); + err = ioctl (nm_dev_sock_get_fd (sk), SIOCGIFADDR, &req); + nm_dev_sock_close (sk); if (err != 0) return; @@ -1414,17 +1463,18 @@ void nm_device_get_ip6_address(NMDevice *dev) * Get a device's hardware address * */ -void nm_device_get_hw_address(NMDevice *dev, unsigned char hw_addr[ETH_ALEN]) +void nm_device_get_hw_address(NMDevice *dev, unsigned char *eth_addr) { + g_return_if_fail (eth_addr != NULL); g_return_if_fail (dev != NULL); - memcpy (hw_addr, dev->hw_addr, ETH_ALEN); + memcpy (eth_addr, dev->hw_addr, ETH_ALEN); } void nm_device_update_hw_address (NMDevice *dev) { struct ifreq req; - int sk; + NMSock *sk; int err; g_return_if_fail (dev != NULL); @@ -1438,17 +1488,17 @@ void nm_device_update_hw_address (NMDevice *dev) return; } - if ((sk = nm_device_open_sock ()) < 0) + if ((sk = nm_dev_sock_open (dev, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) return; memset (&req, 0, sizeof (struct ifreq)); strncpy ((char *)(&req.ifr_name), nm_device_get_iface (dev), strlen (nm_device_get_iface (dev))); - err = ioctl (sk, SIOCGIFHWADDR, &req); - close (sk); + err = ioctl (nm_dev_sock_get_fd (sk), SIOCGIFHWADDR, &req); + nm_dev_sock_close (sk); if (err != 0) return; - memcpy (dev->hw_addr, req.ifr_hwaddr.sa_data, ETH_ALEN); + memcpy (dev->hw_addr, req.ifr_hwaddr.sa_data, ETH_ALEN); } @@ -1461,8 +1511,7 @@ void nm_device_update_hw_address (NMDevice *dev) static void nm_device_set_up_down (NMDevice *dev, gboolean up) { struct ifreq ifr; - int sk; - int err; + NMSock *sk; guint32 flags = up ? IFF_UP : ~IFF_UP; g_return_if_fail (dev != NULL); @@ -1474,17 +1523,12 @@ static void nm_device_set_up_down (NMDevice *dev, gboolean up) return; } - if (nm_device_get_driver_support_level (dev) == NM_DRIVER_UNSUPPORTED) - return; - - sk = nm_device_open_sock (); - if (sk < 0) + if ((sk = nm_dev_sock_open (dev, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) return; /* Get flags already there */ strcpy (ifr.ifr_name, nm_device_get_iface (dev)); - err = ioctl (sk, SIOCGIFFLAGS, &ifr); - if (!err) + if (ioctl (nm_dev_sock_get_fd (sk), SIOCGIFFLAGS, &ifr) != -1) { /* If the interface doesn't have those flags already, * set them on it. @@ -1493,7 +1537,7 @@ static void nm_device_set_up_down (NMDevice *dev, gboolean up) { ifr.ifr_flags &= ~IFF_UP; ifr.ifr_flags |= IFF_UP & flags; - if ((err = ioctl (sk, SIOCSIFFLAGS, &ifr))) + if (ioctl (nm_dev_sock_get_fd (sk), SIOCSIFFLAGS, &ifr) == -1) syslog (LOG_ERR, "nm_device_set_up_down() could not bring device %s %s. errno = %d", nm_device_get_iface (dev), (up ? "up" : "down"), errno ); } /* Make sure we have a valid MAC address, some cards reload firmware when they @@ -1505,7 +1549,7 @@ static void nm_device_set_up_down (NMDevice *dev, gboolean up) else syslog (LOG_ERR, "nm_device_set_up_down() could not get flags for device %s. errno = %d", nm_device_get_iface (dev), errno ); - close (sk); + nm_dev_sock_close (sk); } @@ -1513,6 +1557,51 @@ static void nm_device_set_up_down (NMDevice *dev, gboolean up) * Interface state functions: bring up, down, check * */ +gboolean nm_device_is_up (NMDevice *dev) +{ + NMSock *sk; + struct ifreq ifr; + int err; + + g_return_val_if_fail (dev != NULL, FALSE); + + if (dev->test_device) + return (dev->test_device_up); + + if ((sk = nm_dev_sock_open (dev, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) + return (FALSE); + + /* Get device's flags */ + strcpy (ifr.ifr_name, nm_device_get_iface (dev)); + err = ioctl (nm_dev_sock_get_fd (sk), SIOCGIFFLAGS, &ifr); + nm_dev_sock_close (sk); + if (!err) + return (!((ifr.ifr_flags^IFF_UP) & IFF_UP)); + + syslog (LOG_ERR, "nm_device_is_up() could not get flags for device %s. errno = %d", nm_device_get_iface (dev), errno ); + return (FALSE); +} + +gboolean nm_completion_device_is_up_test(int tries, nm_completion_args args) +{ + NMDevice *dev = args[0]; + gboolean *err = args[1]; + gboolean cancelable = (gboolean)args[2]; + + 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); @@ -1520,6 +1609,25 @@ void nm_device_bring_up (NMDevice *dev) nm_device_set_up_down (dev, TRUE); } +gboolean nm_device_bring_up_wait (NMDevice *dev, gboolean cancelable) +{ + gboolean err = FALSE; + nm_completion_args args; + + g_return_val_if_fail (dev != NULL, TRUE); + + nm_device_bring_up (dev); + + args[0] = dev; + args[1] = &err; + args[2] = (void *)cancelable; + nm_wait_for_completion(400, G_USEC_PER_SEC / 200, NULL, + nm_completion_device_is_up_test, args); + 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); @@ -1527,30 +1635,43 @@ void nm_device_bring_down (NMDevice *dev) nm_device_set_up_down (dev, FALSE); } -gboolean nm_device_is_up (NMDevice *dev) +gboolean nm_completion_device_is_down_test(int tries, nm_completion_args args) { - int sk; - struct ifreq ifr; - int err; + NMDevice *dev = args[0]; + gboolean *err = args[1]; + gboolean cancelable = (gboolean)args[2]; - g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (dev != NULL, TRUE); + g_return_val_if_fail (err != NULL, TRUE); - if (dev->test_device) - return (dev->test_device_up); + *err = FALSE; + if (cancelable && nm_device_activation_handle_cancel (dev)) + { + *err = TRUE; + return TRUE; + } + if (!nm_device_is_up (dev)) + return TRUE; + return FALSE; +} - sk = nm_device_open_sock (); - if (sk < 0) - return (FALSE); +gboolean nm_device_bring_down_wait (NMDevice *dev, gboolean cancelable) +{ + gboolean err = FALSE; + nm_completion_args args; - /* Get device's flags */ - strcpy (ifr.ifr_name, nm_device_get_iface (dev)); - err = ioctl (sk, SIOCGIFFLAGS, &ifr); - close (sk); - if (!err) - return (!((ifr.ifr_flags^IFF_UP) & IFF_UP)); + g_return_val_if_fail (dev != NULL, TRUE); - syslog (LOG_ERR, "nm_device_is_up() could not get flags for device %s. errno = %d", nm_device_get_iface (dev), errno ); - return (FALSE); + nm_device_bring_down (dev); + + args[0] = dev; + args[1] = &err; + args[2] = (void *)cancelable; + nm_wait_for_completion(400, G_USEC_PER_SEC / 200, NULL, + nm_completion_device_is_down_test, args); + if (err) + syslog (LOG_INFO, "failed to bring device down"); + return err; } @@ -1562,21 +1683,18 @@ gboolean nm_device_is_up (NMDevice *dev) */ NMNetworkMode nm_device_get_mode (NMDevice *dev) { - int sk; + NMSock *sk; NMNetworkMode mode = NETWORK_MODE_UNKNOWN; g_return_val_if_fail (dev != NULL, NETWORK_MODE_UNKNOWN); g_return_val_if_fail (nm_device_is_wireless (dev), NETWORK_MODE_UNKNOWN); /* Force the card into Managed/Infrastructure mode */ - sk = iw_sockets_open (); - if (sk >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { struct iwreq wrq; - int err; - err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCGIWMODE, &wrq); - if (err == 0) + if (iw_get_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCGIWMODE, &wrq) == 0) { switch (wrq.u.mode) { @@ -1591,8 +1709,8 @@ NMNetworkMode nm_device_get_mode (NMDevice *dev) } } else - syslog (LOG_ERR, "nm_device_get_mode (%s): error setting card to Infrastructure mode. errno = %d", nm_device_get_iface (dev), errno); - close (sk); + syslog (LOG_ERR, "nm_device_get_mode (%s): error getting card mode. errno = %d", nm_device_get_iface (dev), errno); + nm_dev_sock_close (sk); } return (mode); @@ -1607,8 +1725,8 @@ NMNetworkMode nm_device_get_mode (NMDevice *dev) */ gboolean nm_device_set_mode (NMDevice *dev, const NMNetworkMode mode) { - int sk; - gboolean success = FALSE; + NMSock *sk; + gboolean success = FALSE; g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (nm_device_is_wireless (dev), FALSE); @@ -1618,11 +1736,9 @@ gboolean nm_device_set_mode (NMDevice *dev, const NMNetworkMode mode) return TRUE; /* Force the card into Managed/Infrastructure mode */ - sk = iw_sockets_open (); - if (sk >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { struct iwreq wreq; - int err; gboolean mode_good = FALSE; switch (mode) @@ -1641,13 +1757,15 @@ gboolean nm_device_set_mode (NMDevice *dev, const NMNetworkMode mode) } if (mode_good) { - err = iw_set_ext (sk, nm_device_get_iface (dev), SIOCSIWMODE, &wreq); - if (err == 0) + if (iw_set_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCSIWMODE, &wreq) == 0) success = TRUE; else - syslog (LOG_ERR, "nm_device_set_mode (%s): error setting card to Infrastructure mode. errno = %d", nm_device_get_iface (dev), errno); + syslog (LOG_ERR, "nm_device_set_mode (%s): error setting card to %s mode. errno = %d", + nm_device_get_iface (dev), + mode == NETWORK_MODE_INFRA ? "Infrastructure" : (mode == NETWORK_MODE_ADHOC ? "adhoc" : "unknown"), + errno); } - close (sk); + nm_dev_sock_close (sk); } return (success); @@ -1660,7 +1778,7 @@ gboolean nm_device_set_mode (NMDevice *dev, const NMNetworkMode mode) * Schedule an idle routine in the main thread to finish the activation. * */ -void nm_device_activation_schedule_finish (NMDevice *dev, DeviceStatus activation_result) +void nm_device_activation_schedule_finish (NMDevice *dev, NMAccessPoint *failed_ap, DeviceStatus activation_result) { GSource *source = NULL; NMActivationResult *result = NULL; @@ -1671,6 +1789,7 @@ void nm_device_activation_schedule_finish (NMDevice *dev, DeviceStatus activatio result = g_malloc0 (sizeof (NMActivationResult)); nm_device_ref (dev); /* Ref device for idle handler */ result->dev = dev; + result->failed_ap = failed_ap; result->result = activation_result; source = g_idle_source_new (); @@ -1749,6 +1868,46 @@ static gboolean nm_device_activation_handle_cancel (NMDevice *dev) return (FALSE); } +static gboolean nm_dwwfl_test (int tries, nm_completion_args args) +{ + NMDevice *dev = args[0]; + guint *assoc_count = args[1]; + double *last_freq = args[2]; + char *essid = args[3]; + int required = (int)args[4]; + + 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 +1918,79 @@ 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 }; + nm_completion_args args; + + /* 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; - - /* 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); - - if ((cur_freq == last_freq) && assoc && !strcmp (essid, cur_essid)) - assoc_count++; - else - assoc_count = 0; - last_freq = cur_freq; + /* 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); + + /* 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; + + /* 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. */ + args[0] = dev; + args[1] = &assoc; + args[2] = &last_freq; + args[3] = (void *)essid; + args[4] = (void *)(required_tries * 2); + nm_wait_for_timeout (&timeout, G_USEC_PER_SEC / delay, + nm_dwwfl_test, nm_dwwfl_test, args); - 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, nm_completion_args args) +{ + NMDevice *dev = args[0]; + gboolean *err = args[1]; - /* 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; + nm_completion_args args; - return (link); + g_return_val_if_fail (dev != NULL, TRUE); + + args[0] = dev; + args[1] = &err; + nm_wait_for_completion (max_cycles, delay, NULL, nm_device_link_test, args); + return !err; } @@ -1836,10 +2015,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 +2055,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 @@ -1907,7 +2088,8 @@ static gboolean nm_device_activate_wireless_adhoc (NMDevice *dev, NMAccessPoint int num_freqs = 0, i; double freq_to_use = 0; iwrange range; - int sk; + NMSock *sk; + int err; g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (ap != NULL, FALSE); @@ -1936,15 +2118,13 @@ static gboolean nm_device_activate_wireless_adhoc (NMDevice *dev, NMAccessPoint } nm_ap_list_iter_free (iter); - if ((sk = iw_sockets_open ()) < 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL)) == NULL) return FALSE; - if (iw_get_range_info (sk, nm_device_get_iface (dev), &range) < 0) - { - close (sk); + err = iw_get_range_info (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), &range); + nm_dev_sock_close (sk); + if (err < 0) return FALSE; - } - close (sk); /* Ok, find the first non-zero freq in our table and use it. * For now we only try to use a channel in the 802.11b channel @@ -2070,6 +2250,82 @@ void invalidate_ap (NMDevice *dev, NMAccessPoint *ap) } +/* this gets called without the scan mutex held */ +static gboolean nm_wa_test (int tries, nm_completion_args args) +{ + NMDevice *dev = args[0]; + NMAccessPoint **best_ap = args[1]; + gboolean *err = args[2]; + + 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; + } + else + { + /* Since scanning runs in the device thread, we block scans + * during device activation. So we need to run a scan periodically + * during activation too. + */ + GTimeVal cur_time; + + /* If the last scan was done more than 15s before, do another one. */ + g_get_current_time (&cur_time); + if (cur_time.tv_sec >= dev->options.wireless.last_scan + 15) + { + NMWirelessScanCB *scan_cb = g_malloc0 (sizeof (NMWirelessScanCB)); + + scan_cb->dev = dev; + scan_cb->reschedule = FALSE; + nm_device_wireless_scan (scan_cb); + } + } + + return FALSE; +} + + +static gboolean nm_dukr_test (int tries, nm_completion_args args) +{ + NMDevice *dev = args[0]; + gboolean *err = args[1]; + + g_return_val_if_fail (dev != NULL, TRUE); + g_return_val_if_fail (err != NULL, TRUE); + + *err = TRUE; + + if (nm_device_activation_handle_cancel (dev)) + return TRUE; + if (dev->options.wireless.user_key_received) + { + *err = FALSE; + return TRUE; + } + return FALSE; +} + + /* * nm_device_activate_wireless * @@ -2080,12 +2336,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; + nm_completion_args args; g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (dev->app_data != NULL, FALSE); @@ -2095,9 +2352,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,30 +2363,23 @@ 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; - } - 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)); + /* Get a valid "best" access point we should connect to. */ + nm_device_set_now_scanning (dev, TRUE); - /* 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)); + /* Get an access point to connect to */ + args[0] = dev; + args[1] = &best_ap; + args[2] = &err; + nm_wait_for_completion (NM_COMPLETION_TRIES_INFINITY, G_USEC_PER_SEC / 50, + nm_wa_test, NULL, args); + 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; + } + syslog (LOG_ERR, "Activation (%s/wireless): found access point '%s' to use.", nm_device_get_iface (dev), nm_ap_get_essid (best_ap)); /* We grab the scan mutex so that scanning cannot screw up our link detection, since * a scan can change most any attribute on the card for a period of time. @@ -2155,6 +2403,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); @@ -2173,9 +2423,11 @@ need_key: /* Wait for the key to come back */ syslog (LOG_DEBUG, "Activation (%s/wireless): asking for user key.", nm_device_get_iface (dev)); - while (!dev->options.wireless.user_key_received && !dev->quit_activation) - g_usleep (G_USEC_PER_SEC / 2); + args[0] = dev; + args[1] = &err; + nm_wait_for_completion (NM_COMPLETION_TRIES_INFINITY, + G_USEC_PER_SEC / 20, nm_dukr_test, nm_dukr_test, args); syslog (LOG_DEBUG, "Activation (%s/wireless): user key received.", nm_device_get_iface (dev)); /* Done waiting, grab lock again */ @@ -2241,6 +2493,12 @@ try_connect: nm_device_get_iface (dev), nm_ap_get_essid (best_ap) ? nm_ap_get_essid (best_ap) : "(none)"); } + /* Don't try other APs for non-scanning devices. + * User must pick a new one manually. + */ + if (!nm_device_get_supports_wireless_scan (dev)) + goto out; + /* All applicable modes failed, invalidate current best_ap and get a new one */ invalidate_ap (dev, best_ap); goto get_ap; @@ -2250,8 +2508,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 +2524,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; @@ -2281,6 +2545,12 @@ try_connect: } else { + /* Don't try other APs for non-scanning devices. + * User must pick a new one manually. + */ + if (!nm_device_get_supports_wireless_scan (dev)) + goto out; + /* All applicable modes failed, invalidate current best_ap and get a new one */ invalidate_ap (dev, best_ap); goto get_ap; @@ -2291,7 +2561,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) { @@ -2350,7 +2623,10 @@ static gboolean nm_device_activation_configure_ip (NMDevice *dev, gboolean do_on else { /* Manually set up the device */ + nm_system_device_clear_ip4_nameservers (dev); + nm_system_device_clear_domain_searches (dev); success = nm_system_device_setup_static_ip4_config (dev); + nm_device_update_ip4_address (dev); } if (success) @@ -2375,6 +2651,7 @@ static gboolean nm_device_activate (gpointer user_data) NMDevice *dev = (NMDevice *)user_data; gboolean success = FALSE; gboolean finished = FALSE; + NMAccessPoint *failed_best_ap = NULL; g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (dev->app_data != NULL, FALSE); @@ -2421,10 +2698,15 @@ static gboolean nm_device_activate (gpointer user_data) out: syslog (LOG_DEBUG, "Activation (%s) ended.\n", nm_device_get_iface (dev)); + if (finished) + { + if (nm_device_is_wireless (dev) && !success) + failed_best_ap = nm_device_get_best_ap (dev); + } dev->activating = FALSE; dev->quit_activation = FALSE; if (finished) - nm_device_activation_schedule_finish (dev, success ? DEVICE_NOW_ACTIVE : DEVICE_ACTIVATION_FAILED); + nm_device_activation_schedule_finish (dev, failed_best_ap, success ? DEVICE_NOW_ACTIVE : DEVICE_ACTIVATION_FAILED); return FALSE; } @@ -2458,6 +2740,35 @@ gboolean nm_device_activation_should_cancel (NMDevice *dev) } +static gboolean nm_ac_test (int tries, nm_completion_args args) +{ + NMDevice *dev = args[0]; + + 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 * @@ -2466,6 +2777,8 @@ gboolean nm_device_activation_should_cancel (NMDevice *dev) */ void nm_device_activation_cancel (NMDevice *dev) { + nm_completion_args args; + g_return_if_fail (dev != NULL); if (nm_device_is_activating (dev)) @@ -2477,18 +2790,9 @@ 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); - } + args[0] = dev; + nm_wait_for_completion(NM_COMPLETION_TRIES_INFINITY, + G_USEC_PER_SEC / 20, nm_ac_test, NULL, args); syslog (LOG_DEBUG, "nm_device_activation_cancel(%s): cancelled.", nm_device_get_iface (dev)); } } @@ -2854,6 +3158,22 @@ void nm_device_update_best_ap (NMDevice *dev) g_return_if_fail (dev->app_data != NULL); g_return_if_fail (nm_device_is_wireless (dev)); + /* Devices that can't scan don't do anything automatic. + * The user must choose the access point from the menu. + */ + if (!nm_device_get_supports_wireless_scan (dev)) + { + /* If we lost a link to the AP, clear it out. + * + * FIXME: take samples over 5 seconds or so of the + * whether or not the link is active and only blow away + * the best_ap if its been down for 5 seconds or more. + */ + if (!nm_device_get_link_active (dev)) + nm_device_set_best_ap (dev, NULL); + return; + } + if (!(ap_list = nm_device_ap_list_get (dev))) return; @@ -2979,6 +3299,13 @@ static gboolean nm_device_wireless_force_use (NMDevice *dev, const char *essid, nm_ap_list_append_ap (nm_device_ap_list_get (dev), ap); nm_ap_unref (ap); } + else + { + /* If the AP is in the ignore list, we have to remove it since + * the User Knows What's Best. + */ + nm_ap_list_remove_ap_by_essid (dev->app_data->invalid_ap_list, nm_ap_get_essid (ap)); + } /* Now that this AP has an essid, copy over encryption keys and whatnot */ if ((tmp_ap = nm_ap_list_get_ap_by_essid (dev->app_data->allowed_ap_list, nm_ap_get_essid (ap)))) @@ -3031,9 +3358,11 @@ gboolean nm_device_force_use (gpointer user_data) out: /* Function that scheduled us must ref the device */ - nm_device_unref (cb_data->dev); + if (cb_data->dev) + nm_device_unref (cb_data->dev); + if (app_data) + app_data->forcing_device = FALSE; - app_data->forcing_device = FALSE; g_free (cb_data); return FALSE; } @@ -3062,86 +3391,6 @@ void nm_device_schedule_force_use (NMDevice *dev, const char *network, const cha /* - * nm_device_do_pseudo_scan - * - * Brute-force the allowed access point list to find one that works, if any. - * - * FIXME - * There's probably a better way to do the non-scanning access point discovery - * than brute forcing it like this, but that makes the state machine here oh so - * much more complicated. - */ -static void nm_device_do_pseudo_scan (NMDevice *dev) -{ - NMAPListIter *iter; - NMAccessPoint *ap; - - g_return_if_fail (dev != NULL); - g_return_if_fail (dev->app_data != NULL); - - /* Test devices shouldn't get here since we fake the AP list earlier */ - g_return_if_fail (!dev->test_device); - - nm_device_ref (dev); - - if (!(iter = nm_ap_list_iter_new (dev->app_data->allowed_ap_list))) - return; - - nm_device_set_essid (dev, ""); - while ((ap = nm_ap_list_iter_next (iter))) - { - gboolean valid = FALSE; - struct ether_addr save_ap_addr; - struct ether_addr cur_ap_addr; - - if (!nm_device_is_up (dev)); - nm_device_bring_up (dev); - - /* Save the MAC address */ - nm_device_get_ap_address (dev, &save_ap_addr); - - if (nm_ap_get_enc_key_source (ap)) - { - char *hashed_key = nm_ap_get_enc_key_hashed (ap); - nm_device_set_enc_key (dev, hashed_key, NM_DEVICE_AUTH_METHOD_SHARED_KEY); - g_free (hashed_key); - } - else - nm_device_set_enc_key (dev, NULL, NM_DEVICE_AUTH_METHOD_NONE); - 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)); - - /* Do we have a valid MAC address? */ - nm_device_get_ap_address (dev, &cur_ap_addr); - valid = nm_ethernet_address_is_valid (&cur_ap_addr); - - /* If the ap address we had before, and the ap address we - * have now, are the same, AP is invalid. Certain cards (orinoco) - * will let the essid change, but the the card won't actually de-associate - * from the previous access point if it can't associate with the new one - * (ie signal too weak, etc). - */ - if (valid && (memcmp (&save_ap_addr, &cur_ap_addr, sizeof (struct ether_addr)) == 0)) - valid = FALSE; - - if (valid) - { - syslog(LOG_INFO, "%s: setting AP '%s' best", nm_device_get_iface (dev), nm_ap_get_essid (ap)); - - nm_device_set_best_ap (dev, ap); - nm_policy_schedule_state_update (dev->app_data); - break; - } - } - - nm_ap_list_iter_free (iter); - nm_device_unref (dev); -} - - -/* * nm_device_fake_ap_list * * Fake the access point list, used for test devices. @@ -3211,14 +3460,19 @@ static void nm_device_fake_ap_list (NMDevice *dev) */ static void nm_device_wireless_schedule_scan (NMDevice *dev) { - GSource *wscan_source; - guint wscan_source_id; + GSource *wscan_source; + guint wscan_source_id; + NMWirelessScanCB *scan_cb; g_return_if_fail (dev != NULL); g_return_if_fail (nm_device_is_wireless (dev)); + scan_cb = g_malloc0 (sizeof (NMWirelessScanCB)); + scan_cb->dev = dev; + scan_cb->reschedule = TRUE; + wscan_source = g_timeout_source_new (dev->options.wireless.scan_interval * 1000); - g_source_set_callback (wscan_source, nm_device_wireless_scan, dev, NULL); + g_source_set_callback (wscan_source, nm_device_wireless_scan, scan_cb, NULL); wscan_source_id = g_source_attach (wscan_source, dev->context); g_source_unref (wscan_source); } @@ -3236,7 +3490,6 @@ static gboolean nm_device_wireless_process_scan_results (gpointer user_data) NMWirelessScanResults *results = (NMWirelessScanResults *)user_data; NMDevice *dev; wireless_scan *tmp_ap; - gboolean have_blank_essids = FALSE; NMAPListIter *iter; GTimeVal cur_time; gboolean list_changed = FALSE; @@ -3244,26 +3497,9 @@ static gboolean nm_device_wireless_process_scan_results (gpointer user_data) g_return_val_if_fail (results != NULL, FALSE); dev = results->dev; - if (!dev || !results->scan_head.result) return FALSE; - /* Test devices get their info faked */ - if (dev->test_device) - { - nm_device_fake_ap_list (dev); - return FALSE; - } - - /* Devices that don't support scanning have their pseudo-scanning done in - * the main thread anyway. - */ - if (!nm_device_get_supports_wireless_scan (dev)) - { - nm_device_do_pseudo_scan (dev); - return FALSE; - } - g_get_current_time (&cur_time); /* Translate iwlib scan results to NM access point list */ @@ -3346,7 +3582,7 @@ static gboolean nm_device_wireless_process_scan_results (gpointer user_data) { /* Handle dbus signals that we need to broadcast when the AP is added to the list or changes * strength. - */ + */ if (new) { nm_dbus_signal_wireless_network_change (dev->app_data->dbus_connection, dev, nm_ap, @@ -3419,6 +3655,56 @@ static gboolean nm_device_wireless_process_scan_results (gpointer user_data) } +static gboolean nm_completion_scan_has_results (int tries, nm_completion_args args) +{ + NMDevice *dev = args[0]; + gboolean *err = args[1]; + NMSock *sk = args[2]; + NMWirelessScanResults *scan_results = args[3]; + 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 (nm_dev_sock_get_fd (sk), (char *)nm_device_get_iface (dev), WIRELESS_EXT, &(scan_results->scan_head)); + *err = FALSE; + if (rc == -1 && errno == ETIME) + { + /* Scans take time. iw_scan's timeout is 15 seconds, so if the card hasn't returned + * scan results after two consecutive runs of iw_scan(), the card sucks. + */ + if (tries >= 1) + { + 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; + } + else + { + /* Give the card one more chance to return scan results */ + scan_results->scan_head.result = NULL; + return 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 * @@ -3427,39 +3713,71 @@ static gboolean nm_device_wireless_process_scan_results (gpointer user_data) */ static gboolean nm_device_wireless_scan (gpointer user_data) { - NMDevice *dev = (NMDevice *)(user_data); - int sk; + NMWirelessScanCB *scan_cb = (NMWirelessScanCB *)(user_data); + NMDevice *dev = NULL; NMWirelessScanResults *scan_results = NULL; - g_return_val_if_fail (dev != NULL, FALSE); - g_return_val_if_fail (dev->app_data != NULL, FALSE); + g_return_val_if_fail (scan_cb != NULL, FALSE); - /* We don't scan on test devices or devices that don't have scanning support */ - if (dev->test_device || !nm_device_get_supports_wireless_scan (dev)) + dev = scan_cb->dev; + if (!dev || !dev->app_data) + { + g_free (scan_cb); return FALSE; + } + + /* Reschedule if scanning is off, or if scanning is AUTO and we are + * associated to an access point. + */ + if ( (dev->app_data->scanning_method == NM_SCAN_METHOD_NEVER) + || ( (dev->app_data->scanning_method == NM_SCAN_METHOD_WHEN_UNASSOCIATED) + && (dev->app_data->active_device == dev) + && nm_device_is_activating(dev))) + { + dev->options.wireless.scan_interval = 10; + goto reschedule; + } - /* Just reschedule ourselves if scanning or all wireless is disabled */ - if ( (dev->app_data->scanning_enabled == FALSE) - || (dev->app_data->wireless_enabled == FALSE)) + /* Reschedule ourselves if all wireless is disabled, we're asleep, + * or we are currently activating. + */ + if ( (dev->app_data->wireless_enabled == FALSE) + || (dev->app_data->asleep == TRUE)) { dev->options.wireless.scan_interval = 10; goto reschedule; } + /* Test devices get a fake ap list */ + if (dev->test_device) + { + nm_device_fake_ap_list (dev); + dev->options.wireless.scan_interval = 20; + goto reschedule; + } + /* Grab the scan mutex */ if (nm_try_acquire_mutex (dev->options.wireless.scan_mutex, __FUNCTION__)) { + NMSock *sk; + 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__); + goto reschedule; + } - if ((sk = iw_sockets_open ()) >= 0) + if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) { - 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; + nm_completion_args args; orig_mode = nm_device_get_mode (dev); if (orig_mode == NETWORK_MODE_ADHOC) @@ -3475,20 +3793,13 @@ 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)); + + args[0] = dev; + args[1] = &err; + args[2] = sk; + args[3] = scan_results; + nm_wait_for_completion(max_wait, max_wait/20, + nm_completion_scan_has_results, NULL, args); nm_device_set_mode (dev, orig_mode); /* Only set frequency if ad-hoc mode */ @@ -3498,7 +3809,13 @@ static gboolean nm_device_wireless_scan (gpointer user_data) nm_device_set_bitrate (dev, orig_rate); } - close (sk); + nm_dev_sock_close (sk); + + if (!scan_results->scan_head.result) + { + g_free (scan_results); + scan_results = NULL; + } } nm_unlock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__); } @@ -3511,17 +3828,23 @@ static gboolean nm_device_wireless_scan (gpointer user_data) { guint scan_process_source_id = 0; GSource *scan_process_source = g_idle_source_new (); + GTimeVal cur_time; scan_results->dev = dev; g_source_set_callback (scan_process_source, nm_device_wireless_process_scan_results, scan_results, NULL); scan_process_source_id = g_source_attach (scan_process_source, dev->app_data->main_context); g_source_unref (scan_process_source); + + g_get_current_time (&cur_time); + dev->options.wireless.last_scan = cur_time.tv_sec; } reschedule: /* Make sure we reschedule ourselves so we keep scanning */ - nm_device_wireless_schedule_scan (dev); + if (scan_cb->reschedule) + nm_device_wireless_schedule_scan (dev); + g_free (scan_cb); return FALSE; } @@ -3613,29 +3936,29 @@ typedef u_int64_t u64; static gboolean supports_ethtool_carrier_detect (NMDevice *dev) { - int sk; + NMSock *sk; struct ifreq ifr; gboolean supports_ethtool = FALSE; struct ethtool_cmd edata; g_return_val_if_fail (dev != NULL, FALSE); - if ((sk = socket (AF_INET, SOCK_DGRAM, 0)) < 0) + if ((sk = nm_dev_sock_open (dev, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) { - syslog (LOG_ERR, "cannot open socket on interface %s for MII detect; errno=%d", nm_device_get_iface (dev), errno); + syslog (LOG_ERR, "cannot open socket on interface %s for ethtool detect; errno=%d", nm_device_get_iface (dev), errno); return (FALSE); } strncpy (ifr.ifr_name, nm_device_get_iface (dev), sizeof(ifr.ifr_name)-1); edata.cmd = ETHTOOL_GLINK; ifr.ifr_data = (char *) &edata; - if (ioctl(sk, SIOCETHTOOL, &ifr) == -1) + if (ioctl (nm_dev_sock_get_fd (sk), SIOCETHTOOL, &ifr) == -1) goto out; supports_ethtool = TRUE; out: - close (sk); + nm_dev_sock_close (sk); return (supports_ethtool); } @@ -3646,17 +3969,17 @@ out: /**************************************/ #include <linux/mii.h> -static int mdio_read (int sk, struct ifreq *ifr, int location) +static int mdio_read (NMSock *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 != NULL, -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 (nm_dev_sock_get_fd (sk), SIOCGMIIREG, ifr) < 0) return -1; return (mii->val_out); @@ -3664,29 +3987,29 @@ static int mdio_read (int sk, struct ifreq *ifr, int location) static gboolean supports_mii_carrier_detect (NMDevice *dev) { - int sk; + NMSock *sk; struct ifreq ifr; int bmsr; gboolean supports_mii = FALSE; g_return_val_if_fail (dev != NULL, FALSE); - if ((sk = socket (AF_INET, SOCK_DGRAM, 0)) < 0) + if ((sk = nm_dev_sock_open (dev, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) { syslog (LOG_ERR, "cannot open socket on interface %s for MII detect; errno=%d", nm_device_get_iface (dev), errno); return (FALSE); } strncpy (ifr.ifr_name, nm_device_get_iface (dev), sizeof(ifr.ifr_name)-1); - if (ioctl(sk, SIOCGMIIPHY, &ifr) < 0) + if (ioctl (nm_dev_sock_get_fd (sk), SIOCGMIIPHY, &ifr) < 0) goto out; /* If we can read the BMSR register, we assume that the card supports MII link detection */ - bmsr = mdio_read(sk, &ifr, MII_BMSR); + bmsr = mdio_read (sk, &ifr, MII_BMSR); supports_mii = (bmsr != -1) ? TRUE : FALSE; out: - close (sk); + nm_dev_sock_close (sk); return (supports_mii); } diff --git a/src/NetworkManagerDevice.h b/src/NetworkManagerDevice.h index def2cc93fb..339290d9e7 100644 --- a/src/NetworkManagerDevice.h +++ b/src/NetworkManagerDevice.h @@ -70,7 +70,7 @@ NMNetworkMode nm_device_get_mode (NMDevice *dev); guint32 nm_device_get_ip4_address (NMDevice *dev); void nm_device_update_ip4_address (NMDevice *dev); -void nm_device_get_hw_address (NMDevice *dev, unsigned char hw_addr[ETH_ALEN]); +void nm_device_get_hw_address (NMDevice *dev, unsigned char *eth_addr); void nm_device_update_hw_address (NMDevice *dev); void nm_device_get_ip6_address (NMDevice *dev); @@ -121,6 +121,7 @@ void nm_device_ap_list_clear (NMDevice *dev); struct NMAccessPointList *nm_device_ap_list_get (NMDevice *dev); NMAccessPoint *nm_device_ap_list_get_ap_by_essid (NMDevice *dev, const char *essid); NMAccessPoint *nm_device_ap_list_get_ap_by_address(NMDevice *dev, const struct ether_addr *addr); +void nm_device_copy_allowed_to_dev_list (NMDevice *dev, struct NMAccessPointList *allowed_list); /* System config data accessors */ gboolean nm_device_config_get_use_dhcp (NMDevice *dev); diff --git a/src/NetworkManagerDevicePrivate.h b/src/NetworkManagerDevicePrivate.h index 16d6948c56..610bef4c7d 100644 --- a/src/NetworkManagerDevicePrivate.h +++ b/src/NetworkManagerDevicePrivate.h @@ -49,6 +49,7 @@ typedef struct NMDeviceWirelessOptions GMutex *scan_mutex; NMAccessPointList *ap_list; guint8 scan_interval; /* seconds */ + guint32 last_scan; NMAccessPoint *best_ap; GMutex *best_ap_mutex; @@ -105,7 +106,7 @@ struct NMDevice GMainContext *context; GMainLoop *loop; - gboolean worker_done; + GThread *worker; gboolean worker_started; guint renew_timeout; guint rebind_timeout; diff --git a/src/NetworkManagerMain.h b/src/NetworkManagerMain.h index 18b424eb77..122fad232f 100644 --- a/src/NetworkManagerMain.h +++ b/src/NetworkManagerMain.h @@ -64,8 +64,9 @@ typedef struct NMData gboolean forcing_device; - gboolean scanning_enabled; + NMWirelessScanMethod scanning_method; gboolean wireless_enabled; + gboolean asleep; struct NMAccessPointList *allowed_ap_list; struct NMAccessPointList *invalid_ap_list; diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 71910fdf68..a5b845c881 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -165,6 +165,12 @@ static NMDevice * nm_policy_get_best_device (NMDevice *switch_to_dev, NMData *da if (should_lock_on_activate) *should_lock_on_activate = FALSE; + if (data->asleep == TRUE) + { + data->active_device_locked = FALSE; + return NULL; + } + /* Prefer a device forced on us by the user */ if (switch_to_dev && !nm_device_get_removed (switch_to_dev)) { @@ -227,6 +233,7 @@ gboolean nm_policy_activation_finish (gpointer user_data) { NMActivationResult *result = (NMActivationResult *)user_data; NMDevice *dev = NULL; + NMAccessPoint *failed_ap = NULL; NMData *data = NULL; g_return_val_if_fail (result != NULL, FALSE); @@ -234,6 +241,8 @@ gboolean nm_policy_activation_finish (gpointer user_data) if (!(dev = result->dev)) goto out; + failed_ap = result->failed_ap; + if (!(data = nm_device_get_app_data (dev))) goto out; @@ -268,22 +277,29 @@ gboolean nm_policy_activation_finish (gpointer user_data) nm_dbus_signal_device_status_change (data->dbus_connection, dev, result->result); if (nm_device_is_wireless (dev)) { - NMAccessPoint *ap = nm_device_get_best_ap (dev); - if (ap) + if (failed_ap) { /* Add the AP to the invalid list and force a best ap update */ - nm_ap_list_append_ap (data->invalid_ap_list, ap); + nm_ap_list_append_ap (data->invalid_ap_list, failed_ap); nm_device_update_best_ap (dev); - - /* Unref because nm_device_get_best_ap() refs it before returning. */ - nm_ap_unref (ap); } - syslog (LOG_INFO, "Activation (%s) failed for access point (%s)", nm_device_get_iface (dev), ap ? nm_ap_get_essid (ap) : "(none)"); + + syslog (LOG_INFO, "Activation (%s) failed for access point (%s)", nm_device_get_iface (dev), + failed_ap ? nm_ap_get_essid (failed_ap) : "(none)"); + + /* Failed AP got reffed by nm_device_get_best_ap() during activation, + * must unref it here. + */ + if (failed_ap) + nm_ap_unref (failed_ap); } else syslog (LOG_INFO, "Activation (%s) failed.", nm_device_get_iface (dev)); if (data->active_device == dev) + { + nm_device_unref (dev); data->active_device = NULL; + } nm_device_deactivate (dev, FALSE); break; @@ -468,7 +484,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 +498,27 @@ 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)) + { + if (nm_device_get_supports_wireless_scan (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); + } + else + nm_device_copy_allowed_to_dev_list (dev, data->allowed_ap_list); + + nm_ap_list_remove_duplicate_essids (nm_device_ap_list_get (dev)); + } + } + /* If the active device doesn't have a best_ap already, make it update to * get the new data. */ @@ -490,13 +528,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/NetworkManagerPolicy.h b/src/NetworkManagerPolicy.h index 3a6524118e..c347812935 100644 --- a/src/NetworkManagerPolicy.h +++ b/src/NetworkManagerPolicy.h @@ -29,6 +29,7 @@ typedef struct { NMDevice *dev; + NMAccessPoint *failed_ap; DeviceStatus result; } NMActivationResult; diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index cca0364e50..66445f8fb7 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -41,41 +41,28 @@ #include <glib.h> #include "NetworkManagerSystem.h" #include "NetworkManagerDevice.h" - -static int nm_system_open_sock (void) -{ - int fd; - - /* Try to grab a control socket */ - fd = socket (AF_PACKET, SOCK_PACKET, htons (ETH_P_ALL)); - if (fd >= 0) - return (fd); - - syslog (LOG_ERR, "nm_system_open_sock() could not get network control socket."); - return (-1); -} - +#include "NetworkManagerUtils.h" gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address) { struct ifreq ifr; const char *iface; - int sk; + NMSock *sk; gboolean success = FALSE; struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); g_return_val_if_fail (dev != NULL, FALSE); - iface = nm_device_get_iface (dev); - sk = nm_system_open_sock (); - if (sk < 0) + if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) return FALSE; memset (&ifr, 0, sizeof(struct ifreq)); + + iface = nm_device_get_iface (dev); memcpy (ifr.ifr_name, iface, strlen (iface)); p->sin_family = AF_INET; p->sin_addr.s_addr = ip4_address; - if (ioctl (sk, SIOCSIFADDR, &ifr) == -1) + if (ioctl (nm_dev_sock_get_fd (sk), SIOCSIFADDR, &ifr) == -1) syslog (LOG_ERR,"nm_system_device_set_ip4_address (%s): failed to set IPv4 address!", iface); else { @@ -85,7 +72,7 @@ gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address) ((unsigned char *)&ip4_address)[2], ((unsigned char *)&ip4_address)[3]); } - close (sk); + nm_dev_sock_close (sk); return (success); } @@ -94,27 +81,27 @@ gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask) { struct ifreq ifr; const char *iface; - int sk; + NMSock *sk; gboolean success = FALSE; struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); g_return_val_if_fail (dev != NULL, FALSE); - iface = nm_device_get_iface (dev); - sk = nm_system_open_sock (); - if (sk < 0) + if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) return FALSE; memset (&ifr, 0, sizeof(struct ifreq)); + + iface = nm_device_get_iface (dev); memcpy (ifr.ifr_name, iface, strlen (iface)); p->sin_family = AF_INET; p->sin_addr.s_addr = ip4_netmask; - if (ioctl (sk, SIOCSIFNETMASK, &ifr) == -1) + if (ioctl (nm_dev_sock_get_fd (sk), SIOCSIFNETMASK, &ifr) == -1) syslog (LOG_ERR,"nm_system_device_set_ip4_netmask (%s): failed to set IPv4 netmask! errno = %s", iface, strerror (errno)); else success = TRUE; - close (sk); + nm_dev_sock_close (sk); return (success); } @@ -123,27 +110,26 @@ gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast) { struct ifreq ifr; const char *iface; - int sk; + NMSock *sk; gboolean success = FALSE; struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); g_return_val_if_fail (dev != NULL, FALSE); - iface = nm_device_get_iface (dev); - sk = nm_system_open_sock (); - if (sk < 0) + if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) return FALSE; memset (&ifr, 0, sizeof(struct ifreq)); + iface = nm_device_get_iface (dev); memcpy (ifr.ifr_name, iface, strlen (iface)); p->sin_family = AF_INET; p->sin_addr.s_addr = ip4_broadcast; - if (ioctl (sk, SIOCSIFBRDADDR, &ifr) == -1) - syslog (LOG_ERR,"nm_system_device_set_ip4_netmask (%s): failed to set IPv4 netmask!", iface); + if (ioctl (nm_dev_sock_get_fd (sk), SIOCSIFBRDADDR, &ifr) == -1) + syslog (LOG_ERR,"nm_system_device_set_ip4_netmask (%s): failed to set IPv4 broadcast address!", iface); else success = TRUE; - close (sk); + nm_dev_sock_close (sk); return (success); } @@ -151,18 +137,18 @@ gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast) gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_route) { const char *iface; - int sk; + NMSock *sk; gboolean success = FALSE; struct rtentry rtent; struct sockaddr_in *p; g_return_val_if_fail (dev != NULL, FALSE); - iface = nm_device_get_iface (dev); - sk = nm_system_open_sock (); - if (sk < 0) + if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) return FALSE; + iface = nm_device_get_iface (dev); + memset (&rtent, 0, sizeof (struct rtentry)); p = (struct sockaddr_in *)&rtent.rt_dst; p->sin_family = AF_INET; @@ -178,7 +164,7 @@ gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_rout rtent.rt_window = 0; rtent.rt_flags = RTF_UP | RTF_GATEWAY | ( rtent.rt_window ? RTF_WINDOW : 0); - if (ioctl (sk, SIOCADDRT, &rtent) == -1) + if (ioctl (nm_dev_sock_get_fd (sk), SIOCADDRT, &rtent) == -1) { if (errno == ENETUNREACH) /* possibly gateway is over the bridge */ { /* try adding a route to gateway first */ @@ -197,9 +183,9 @@ gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_rout rtent2.rt_metric = 0; rtent2.rt_flags = RTF_UP | RTF_HOST; - if ( ioctl (sk, SIOCADDRT, &rtent2) == 0 ) + if (ioctl (nm_dev_sock_get_fd (sk), SIOCADDRT, &rtent2) == 0 ) { - if ( ioctl (sk, SIOCADDRT, &rtent) == 0 ) + if (ioctl (nm_dev_sock_get_fd (sk), SIOCADDRT, &rtent) == 0 ) success = TRUE; else syslog (LOG_ERR,"nm_system_device_set_ip4_default_route (%s): failed to set IPv4 default route! errno = %d", iface, errno); @@ -211,7 +197,124 @@ gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_rout else success = TRUE; - close (sk); + nm_dev_sock_close (sk); return (success); } + +gboolean nm_system_device_add_ip4_nameserver (NMDevice *dev, guint32 ip4_nameserver) +{ + gboolean success = FALSE; + char *nameserver; + GError *error = NULL; + NMData *data; + guint id; + + g_return_val_if_fail (dev != NULL, FALSE); + data = nm_device_get_app_data (dev); + g_return_val_if_fail (data != NULL, FALSE); + + nameserver = g_strdup_printf ("%u.%u.%u.%u", + ((unsigned char *)&ip4_nameserver)[0], + ((unsigned char *)&ip4_nameserver)[1], + ((unsigned char *)&ip4_nameserver)[2], + ((unsigned char *)&ip4_nameserver)[3]); + syslog (LOG_WARNING, "Adding nameserver: %s", nameserver); + + if ((id = nm_named_manager_add_nameserver_ipv4 (data->named, nameserver, &error))) + { + data->nameserver_ids = g_list_prepend (data->nameserver_ids, GUINT_TO_POINTER (id)); + success = TRUE; + } + else + { + syslog (LOG_WARNING, "Couldn't add nameserver: %s\n", error->message); + g_clear_error (&error); + } + g_free (nameserver); + + return success; +} + + +void nm_system_device_clear_ip4_nameservers (NMDevice *dev) +{ + GList *elt; + GError *error = NULL; + NMData *data; + + g_return_if_fail (dev != NULL); + data = nm_device_get_app_data (dev); + g_return_if_fail (data != NULL); + + /* Reset our nameserver list */ + for (elt = data->nameserver_ids; elt; elt = elt->next) + { + if (!nm_named_manager_remove_nameserver_ipv4 (data->named, + GPOINTER_TO_UINT (elt->data), + &error)) + { + syslog (LOG_WARNING, "Couldn't remove nameserver: %s", error->message); + g_clear_error (&error); + } + } + g_list_free (data->nameserver_ids); + data->nameserver_ids = NULL; + +} + + +gboolean nm_system_device_add_domain_search (NMDevice *dev, const char *search) +{ + gboolean success = FALSE; + guint id; + GError *error = NULL; + NMData *data; + + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (search != NULL, FALSE); + g_return_val_if_fail (strlen (search) >= 0, FALSE); + + data = nm_device_get_app_data (dev); + g_return_val_if_fail (data != NULL, FALSE); + + syslog (LOG_WARNING, "Adding domain search: %s\n", search); + if ((id = nm_named_manager_add_domain_search (data->named, search, &error))) + { + data->domain_search_ids = g_list_append (data->domain_search_ids, GUINT_TO_POINTER (id)); + success = TRUE; + } + else + { + syslog (LOG_WARNING, "Couldn't add domain search '%s': %s\n", search, error->message); + g_clear_error (&error); + } + + return success; +} + +void nm_system_device_clear_domain_searches (NMDevice *dev) +{ + GError *error = NULL; + GList *elt; + NMData *data; + + g_return_if_fail (dev != NULL); + data = nm_device_get_app_data (dev); + g_return_if_fail (data != NULL); + + /* Reset our domain search list */ + for (elt = data->domain_search_ids; elt; elt = elt->next) + { + if (!nm_named_manager_remove_domain_search (data->named, + GPOINTER_TO_UINT (elt->data), + &error)) + { + syslog (LOG_WARNING, "Couldn't remove domain search: %s\n", error->message); + g_clear_error (&error); + } + } + g_list_free (data->domain_search_ids); + data->domain_search_ids = NULL; +} + diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index 560487146b..4f719031aa 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -52,6 +52,9 @@ gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address); gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask); gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast); gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_route); -gboolean nm_system_device_update_resolv_conf (void *data, int len, const char *domain_name); +gboolean nm_system_device_add_ip4_nameserver (NMDevice *dev, guint32 ip4_nameserver); +void nm_system_device_clear_ip4_nameservers (NMDevice *dev); +gboolean nm_system_device_add_domain_search (NMDevice *dev, const char *search); +void nm_system_device_clear_domain_searches (NMDevice *dev); #endif diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 77b908c32a..4af75a5c27 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -25,11 +25,26 @@ #include <sys/socket.h> #include <linux/sockios.h> #include <syslog.h> +#include <stdarg.h> +#include <sys/time.h> +#include <string.h> +#include <iwlib.h> #include "NetworkManager.h" #include "NetworkManagerUtils.h" +struct NMSock +{ + int fd; + char *func; + char *desc; + NMDevice *dev; +}; + +static GSList *sock_list = NULL; +static GStaticMutex sock_list_mutex = G_STATIC_MUTEX_INIT; + typedef struct MutexDesc { GMutex *mutex; @@ -151,6 +166,141 @@ void nm_unlock_mutex (GMutex *mutex, const char *func) /* + * nm_dev_sock_open + * + * Open a socket to a network device and store some debug info about it. + * + */ +NMSock *nm_dev_sock_open (NMDevice *dev, SockType type, const char *func_name, const char *desc) +{ + NMSock *sock = NULL; + + sock = g_malloc0 (sizeof (NMSock)); + + sock->fd = -1; + + switch (type) + { + case DEV_WIRELESS: + sock->fd = iw_sockets_open (); + break; + + case DEV_GENERAL: + if ((sock->fd = socket (PF_INET, SOCK_DGRAM, 0)) < 0) + if ((sock->fd = socket (PF_PACKET, SOCK_DGRAM, 0)) < 0) + sock->fd = socket (PF_INET6, SOCK_DGRAM, 0); + break; + + case NETWORK_CONTROL: + sock->fd = socket (AF_PACKET, SOCK_PACKET, htons (ETH_P_ALL)); + break; + + default: + break; + } + + if (sock->fd < 0) + { + g_free (sock); + syslog (LOG_ERR, "Could not open control socket for device '%s'.", dev ? nm_device_get_iface (dev) : "none"); + return NULL; + } + + sock->func = func_name ? g_strdup (func_name) : NULL; + sock->desc = desc ? g_strdup (desc) : NULL; + sock->dev = dev; + if (sock->dev) + nm_device_ref (sock->dev); + + /* Add the sock to our global sock list for tracking */ + g_static_mutex_lock (&sock_list_mutex); + sock_list = g_slist_append (sock_list, sock); + g_static_mutex_unlock (&sock_list_mutex); + + return sock; +} + + +/* + * nm_dev_sock_close + * + * Close a socket and free its debug data. + * + */ +void nm_dev_sock_close (NMSock *sock) +{ + GSList *elt; + + g_return_if_fail (sock != NULL); + + close (sock->fd); + g_free (sock->func); + g_free (sock->desc); + if (sock->dev) + nm_device_unref (sock->dev); + + memset (sock, 0, sizeof (NMSock)); + + g_static_mutex_lock (&sock_list_mutex); + for (elt = sock_list; elt; elt = g_slist_next (elt)) + { + NMSock *temp_sock = (NMSock *)(elt->data); + if (temp_sock == sock) + { + sock_list = g_slist_remove_link (sock_list, elt); + g_slist_free (elt); + break; + } + } + g_static_mutex_unlock (&sock_list_mutex); + + g_free (sock); +} + + +/* + * nm_dev_sock_get_fd + * + * Return the fd associated with an NMSock + * + */ +int nm_dev_sock_get_fd (NMSock *sock) +{ + g_return_val_if_fail (sock != NULL, -1); + + return sock->fd; +} + + +/* + * nm_print_open_socks + * + * Print a list of currently open and registered NMSocks. + * + */ +void nm_print_open_socks (void) +{ + GSList *elt = NULL; + int i = 0; + + syslog (LOG_DEBUG, "Open Sockets List:"); + g_static_mutex_lock (&sock_list_mutex); + for (elt = sock_list; elt; elt = g_slist_next (elt)) + { + NMSock *sock = (NMSock *)(elt->data); + if (sock) + { + i++; + syslog (LOG_DEBUG, " %d: %s fd:%d F:'%s' D:'%s'", i, sock->dev ? nm_device_get_iface (sock->dev) : "", + sock->fd, sock->func, sock->desc); + } + } + g_static_mutex_unlock (&sock_list_mutex); + syslog (LOG_DEBUG, "Open Sockets List Done."); +} + + +/* * nm_null_safe_strcmp * * Doesn't freaking segfault if s1/s2 are NULL @@ -169,7 +319,6 @@ int nm_null_safe_strcmp (const char *s1, const char *s2) } - /* * nm_ethernet_address_is_valid * @@ -331,6 +480,10 @@ NMDriverSupportLevel nm_get_wireless_driver_support_level (LibHalContext *ctx, N g_free (driver_name); } + /* Check for carrier detection support */ + if ((level != NM_DRIVER_UNSUPPORTED) && !nm_device_get_supports_wireless_scan (dev)) + level = NM_DRIVER_NO_WIRELESS_SCAN; + return (level); } @@ -381,6 +534,10 @@ NMDriverSupportLevel nm_get_wired_driver_support_level (LibHalContext *ctx, NMDe level = NM_DRIVER_UNSUPPORTED; } + /* Check for carrier detection support */ + if ((level != NM_DRIVER_UNSUPPORTED) && !nm_device_get_supports_carrier_detect(dev)) + level = NM_DRIVER_NO_CARRIER_DETECT; + return (level); } @@ -406,8 +563,13 @@ NMDriverSupportLevel nm_get_driver_support_level (LibHalContext *ctx, NMDevice * switch (level) { - case NM_DRIVER_SEMI_SUPPORTED: - syslog (LOG_INFO, "%s: Driver support level for '%s' is semi-supported", + case NM_DRIVER_NO_CARRIER_DETECT: + syslog (LOG_INFO, "%s: Driver '%s' does not support carrier detection.\n" + "\tYou must switch to it manually.", nm_device_get_iface (dev), driver); + break; + case NM_DRIVER_NO_WIRELESS_SCAN: + syslog (LOG_INFO, "%s: Driver '%s' does not support wireless scanning.\n" + "\tNetworkManager will not be able to fully use the card.", nm_device_get_iface (dev), driver); break; case NM_DRIVER_FULLY_SUPPORTED: @@ -423,3 +585,207 @@ 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, + nm_completion_args 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); + } +} + +/* these should probably be moved to NetworkManagerUtils.h as macros + * since they don't do varargs stuff any more */ +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, + nm_completion_args args) +{ + nm_v_wait_for_completion_or_timeout(max_tries, max_time, + interval_usecs, test_func, + action_func, args); +} + +void nm_wait_for_completion( + const int max_tries, + const guint interval_usecs, + nm_completion_func test_func, + nm_completion_func action_func, + nm_completion_args args) +{ + nm_v_wait_for_completion_or_timeout(max_tries, NULL, + interval_usecs, test_func, + action_func, args); +} + +void nm_wait_for_timeout( + const struct timeval *max_time, + const guint interval_usecs, + nm_completion_func test_func, + nm_completion_func action_func, + nm_completion_args args) +{ + nm_v_wait_for_completion_or_timeout(-1, max_time, interval_usecs, + test_func, action_func, args); +} + +/* you can use these, but they're really just examples */ +gboolean nm_completion_boolean_test(int tries, nm_completion_args args) +{ + gboolean *condition = (gboolean *)args[0]; + char *message = (char *)args[1]; + int log_level = (int)args[2]; + int log_interval = (int)args[3]; + + 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, + nm_completion_args args) +{ + nm_completion_boolean_function_1 condition = args[0]; + char *message = args[1]; + int log_level = (int)args[2]; + int log_interval = (int)args[3]; + u_int64_t arg0; + + memcpy(&arg0, &args[4], sizeof (arg0)); + + 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, + nm_completion_args args) +{ + nm_completion_boolean_function_2 condition = args[0]; + char *message = args[1]; + int log_level = (int)args[2]; + int log_interval = (int)args[3]; + u_int64_t arg0, arg1; + + memcpy(&arg0, &args[4], sizeof (arg0)); + memcpy(&arg1, &args[4]+sizeof (arg0), sizeof (arg1)); + + 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..6def8fe05c 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -27,17 +27,33 @@ #include <syslog.h> #include <net/ethernet.h> #include <iwlib.h> +#include <sys/time.h> +#include <stdarg.h> #include "NetworkManager.h" #include "NetworkManagerMain.h" #include "NetworkManagerDevice.h" +typedef enum SockType +{ + DEV_WIRELESS, + DEV_GENERAL, + NETWORK_CONTROL +} SockType; + +typedef struct NMSock NMSock; + gboolean nm_try_acquire_mutex (GMutex *mutex, const char *func); void nm_lock_mutex (GMutex *mutex, const char *func); void nm_unlock_mutex (GMutex *mutex, const char *func); void nm_register_mutex_desc (GMutex *mutex, char *string); +NMSock * nm_dev_sock_open (NMDevice *dev, SockType type, const char *func_name, const char *desc); +void nm_dev_sock_close (NMSock *sock); +int nm_dev_sock_get_fd (NMSock *sock); +void nm_print_open_socks (void); + int nm_null_safe_strcmp (const char *s1, const char *s2); gboolean nm_ethernet_address_is_valid (struct ether_addr *test_addr); @@ -48,4 +64,42 @@ int nm_spawn_process (char *args); NMDriverSupportLevel nm_get_driver_support_level (LibHalContext *ctx, NMDevice *dev); +#define NM_COMPLETION_TRIES_INFINITY -1 + +typedef void * nm_completion_args[8]; + +typedef gboolean (*nm_completion_func)(int tries, nm_completion_args 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, + nm_completion_args 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, + nm_completion_args args); + +void nm_wait_for_timeout( + const struct timeval *max_time, + const guint interval_usecs, + nm_completion_func test_func, + nm_completion_func action_func, + nm_completion_args args); + +gboolean nm_completion_boolean_test(int tries, nm_completion_args args); +gboolean nm_completion_boolean_function1_test(int tries, + nm_completion_args args); +gboolean nm_completion_boolean_function2_test(int tries, + nm_completion_args args); +#define nm_completion_boolean_function_test nm_completion_boolean_function1_test + #endif diff --git a/src/autoip.c b/src/autoip.c index 92df4a369b..bbdfd0305c 100644 --- a/src/autoip.c +++ b/src/autoip.c @@ -33,6 +33,7 @@ #include "NetworkManager.h" #include "NetworkManagerDevice.h" #include "NetworkManagerMain.h" +#include "NetworkManagerUtils.h" // Times here are in seconds #define LINKLOCAL_ADDR 0xa9fe0000 @@ -56,7 +57,7 @@ static struct ether_addr broadcast_addr = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}} /** * Pick a random link local IP address. */ -static void pick(struct in_addr *ip) +static void pick (struct in_addr *ip) { ip->s_addr = htonl (LINKLOCAL_ADDR | ((abs(random()) % 0xFD00) + (abs(random()) % 0x0100))); @@ -174,7 +175,7 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) arpMessage p; struct ether_addr addr; struct in_addr ip = {0}; - int fd; + NMSock *sk; int nprobes = 0; int nannounce = 0; gboolean success = FALSE; @@ -189,20 +190,20 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) strncpy (saddr.sa_data, nm_device_get_iface (dev), sizeof (saddr.sa_data)); /* open an ARP socket */ - if ((fd = socket (PF_PACKET, SOCK_PACKET, htons (ETH_P_ARP))) < 0) + if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) { syslog (LOG_ERR, "%s: Couldn't open network control socket.", nm_device_get_iface (dev)); goto out; } /* bind to the ARP socket */ - if (bind (fd, &saddr, sizeof (saddr)) < 0) + if (bind (nm_dev_sock_get_fd (sk), &saddr, sizeof (saddr)) < 0) { syslog (LOG_ERR, "%s: Couldn't bind to the device.", nm_device_get_iface (dev)); goto out; } - nm_device_get_hw_address (dev, addr.ether_addr_octet); + nm_device_get_hw_address (dev, &(addr.ether_addr_octet[0])); /* initialize pseudo random selection of IP addresses */ srandom ( (addr.ether_addr_octet[ETHER_ADDR_LEN-4] << 24) | @@ -226,7 +227,7 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) if (nprobes < PROBE_NUM) { syslog (LOG_INFO, "autoip: Sending probe #%d for IP address %s.", nprobes, inet_ntoa (ip)); - arp (fd, &saddr, ARPOP_REQUEST, &addr, null_ip, &null_addr, ip); + arp (nm_dev_sock_get_fd (sk), &saddr, ARPOP_REQUEST, &addr, null_ip, &null_addr, ip); nprobes++; gettimeofday (&timeout, NULL); if (nprobes == PROBE_NUM) @@ -246,7 +247,7 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) else if (nannounce < ANNOUNCE_NUM) { syslog (LOG_INFO, "autoip: Sending announce #%d for IP address %s.", nannounce, inet_ntoa (ip)); - arp (fd, &saddr, ARPOP_REQUEST, &addr, ip, &addr, ip); + arp (nm_dev_sock_get_fd (sk), &saddr, ARPOP_REQUEST, &addr, ip, &addr, ip); nannounce++; gettimeofday (&timeout, NULL); timeout.tv_sec += ANNOUNCE_INTERVAL; @@ -261,7 +262,7 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) } syslog (LOG_INFO, "autoip: Waiting for reply..."); - err = peekfd (dev, fd, &timeout); + err = peekfd (dev, nm_dev_sock_get_fd (sk), &timeout); if ((err == RET_DHCP_ERROR) || (err == RET_DHCP_CEASED)) goto out; @@ -271,7 +272,7 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) syslog (LOG_INFO, "autoip: Got some data to check for reply packet."); /* read ARP packet */ - if (recv (fd, &p, sizeof (p), 0) < 0) + if (recv (nm_dev_sock_get_fd (sk), &p, sizeof (p), 0) < 0) { syslog (LOG_ERR, "autoip: packet receive failure, ignoring it."); continue; @@ -308,7 +309,6 @@ gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip) } out: - if (fd >= 0) - close (fd); + nm_dev_sock_close (sk); return (success); } diff --git a/src/backends/NetworkManagerDebian.c b/src/backends/NetworkManagerDebian.c index b42653669f..51d234103d 100644 --- a/src/backends/NetworkManagerDebian.c +++ b/src/backends/NetworkManagerDebian.c @@ -334,9 +334,10 @@ void nm_system_restart_mdns_responder (void) void nm_system_device_add_ip6_link_address (NMDevice *dev) { char *buf; + char *addr; unsigned char eui[8]; - nm_device_get_hw_address(dev, eui); + nm_device_get_hw_address(dev, &eui[0]); memmove(eui+5, eui+3, 3); eui[3] = 0xff; diff --git a/src/backends/NetworkManagerRedHat.c b/src/backends/NetworkManagerRedHat.c index 21215c8684..899c7c710a 100644 --- a/src/backends/NetworkManagerRedHat.c +++ b/src/backends/NetworkManagerRedHat.c @@ -128,6 +128,102 @@ void nm_system_device_flush_addresses (NMDevice *dev) /* + * get_current_profile_name + * + * Retrieve the current network profile, if any + * + */ +static char *get_current_profile_name (void) +{ + shvarFile * file; + char * buf; + + if (!(file = svNewFile (SYSCONFDIR"/sysconfig/network"))) + return NULL; + + buf = svGetValue (file, "CURRENT_PROFILE"); + if (!buf) + buf = strdup ("default"); + svCloseFile (file); + + return buf; +} + + +/* + * set_ip4_config_from_resolv_conf + * + * Add nameservers and search names from a resolv.conf format file. + * + */ +static void set_ip4_config_from_resolv_conf (NMDevice *dev, const char *filename) +{ + char * contents = NULL; + char ** split_contents = NULL; + char ** split_line = NULL; + int i, len; + + g_return_if_fail (dev != NULL); + g_return_if_fail (filename != NULL); + + if (!g_file_get_contents (filename, &contents, NULL, NULL) || (contents == NULL)) + return; + + if (!(split_contents = g_strsplit (contents, "\n", 0))) + goto out; + + for (split_line = split_contents; *split_line; split_line++) + { + char *line = *split_line; + + /* Ignore comments */ + if (!line || (line[0] == ';')) + continue; + + line = g_strstrip (line); + if ((strncmp (line, "search", 6) == 0) && (strlen (line) > 6)) + { + char *searches = g_strdup (line + 7); + char **split_searches = NULL; + + if (!searches || !strlen (searches)) + continue; + + /* Allow space-separated search domains */ + if ((split_searches = g_strsplit (searches, " ", 0))) + { + char **item = NULL; + int m, srch_len; + + for (item = split_searches; *item; item++) + nm_system_device_add_domain_search (dev, *item); + g_strfreev (split_searches); + } + else + { + /* Only 1 item, add the whole line */ + nm_system_device_add_domain_search (dev, searches); + } + + g_free (searches); + } + else if ((strncmp (line, "nameserver", 10) == 0) && (strlen (line) > 10)) + { + guint32 addr = (guint32) (inet_addr (line + 11)); + + if (addr != (guint32) -1) + nm_system_device_add_ip4_nameserver (dev, addr); + } + } + + g_strfreev (split_contents); + +out: + g_free (contents); +} + + +/* * nm_system_device_setup_static_ip4_config * * Set up the device with a particular IPv4 address/netmask/gateway. @@ -151,6 +247,7 @@ gboolean nm_system_device_setup_static_ip4_config (NMDevice *dev) char *buf; int err; const char *iface; + char * cur_profile_name = get_current_profile_name (); g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (!nm_device_config_get_use_dhcp (dev), FALSE); @@ -207,6 +304,16 @@ gboolean nm_system_device_setup_static_ip4_config (NMDevice *dev) goto error; } g_free (buf); + + if (cur_profile_name) + { + char *filename = g_strdup_printf (SYSCONFDIR"/sysconfig/networking/profiles/%s/resolv.conf", cur_profile_name); + + set_ip4_config_from_resolv_conf (dev, filename); + g_free (filename); + g_free (cur_profile_name); + } + return (TRUE); error: @@ -350,7 +457,7 @@ void nm_system_device_add_ip6_link_address (NMDevice *dev) char *buf; unsigned char eui[8]; - nm_device_get_hw_address(dev, eui); + nm_device_get_hw_address(dev, &eui[0]); memmove(eui+5, eui+3, 3); eui[3] = 0xff; diff --git a/src/backends/shvar.c b/src/backends/shvar.c index 765a77e7c5..01cf395a68 100644 --- a/src/backends/shvar.c +++ b/src/backends/shvar.c @@ -49,12 +49,18 @@ svOpenFile(const char *name, gboolean create) s = g_malloc0(sizeof(shvarFile)); +#if 0 s->fd = open(name, O_RDWR); /* NOT O_CREAT */ if (s->fd == -1) { /* try read-only */ s->fd = open(name, O_RDONLY); /* NOT O_CREAT */ if (s->fd != -1) closefd = 1; } +#else + /* try read-only */ + s->fd = open(name, O_RDONLY); /* NOT O_CREAT */ + if (s->fd != -1) closefd = 1; +#endif s->fileName = g_strdup(name); if (s->fd != -1) { diff --git a/src/nm-dbus-device.c b/src/nm-dbus-device.c index fd7bfbca8b..74228dada2 100644 --- a/src/nm-dbus-device.c +++ b/src/nm-dbus-device.c @@ -25,6 +25,7 @@ #include <dbus/dbus-glib.h> #include <stdarg.h> #include <syslog.h> +#include <netinet/ether.h> #include "NetworkManagerDevice.h" #include "NetworkManagerDbus.h" @@ -88,6 +89,28 @@ static DBusMessage *nm_dbus_device_get_ip4_address (DBusConnection *connection, return reply; } +static DBusMessage *nm_dbus_device_get_hw_address (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + DBusMessage *reply = NULL; + NMDevice *dev; + + g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL); + + dev = data->dev; + if ((reply = dbus_message_new_method_return (message))) + { + struct ether_addr addr; + char char_addr[20]; + + nm_device_get_hw_address (dev, (unsigned char *)&(addr.ether_addr_octet)); + memset (char_addr, 0, 20); + ether_ntoa_r (&addr, &char_addr[0]); + dbus_message_append_args (reply, DBUS_TYPE_STRING, char_addr, DBUS_TYPE_INVALID); + } + + return reply; +} + static DBusMessage *nm_dbus_device_get_mode (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) { DBusMessage *reply = NULL; @@ -240,22 +263,16 @@ static DBusMessage *nm_dbus_device_get_networks (DBusConnection *connection, DBu return reply; } -static DBusMessage *nm_dbus_device_get_supports_carrier_detect (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +static DBusMessage *nm_dbus_device_get_driver_support_level (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) { DBusMessage *reply = NULL; NMDevice *dev; g_return_val_if_fail (data && data->data && data->dev && connection && message, NULL); - /* Wired devices only for now */ dev = data->dev; - if (!nm_device_is_wired (dev)) - { - reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "DeviceNotWired", - "Carrier detection is only supported for wired devices."); - } - else if ((reply = dbus_message_new_method_return (message))) - dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, nm_device_get_supports_carrier_detect (dev), DBUS_TYPE_INVALID); + if ((reply = dbus_message_new_method_return (message))) + dbus_message_append_args (reply, DBUS_TYPE_UINT32, nm_device_get_driver_support_level (dev), DBUS_TYPE_INVALID); return reply; } @@ -301,17 +318,18 @@ NMDbusMethodList *nm_dbus_device_methods_setup (void) { NMDbusMethodList *list = nm_dbus_method_list_new (NULL); - nm_dbus_method_list_add_method (list, "getName", nm_dbus_device_get_name); - nm_dbus_method_list_add_method (list, "getType", nm_dbus_device_get_type); - nm_dbus_method_list_add_method (list, "getHalUdi", nm_dbus_device_get_hal_udi); - nm_dbus_method_list_add_method (list, "getIP4Address", nm_dbus_device_get_ip4_address); - nm_dbus_method_list_add_method (list, "getMode", nm_dbus_device_get_mode); - nm_dbus_method_list_add_method (list, "getStrength", nm_dbus_device_get_strength); - nm_dbus_method_list_add_method (list, "getActiveNetwork", nm_dbus_device_get_active_network); - nm_dbus_method_list_add_method (list, "getNetworks", nm_dbus_device_get_networks); - nm_dbus_method_list_add_method (list, "getLinkActive", nm_dbus_device_get_link_active); - nm_dbus_method_list_add_method (list, "setLinkActive", nm_dbus_device_set_link_active); - nm_dbus_method_list_add_method (list, "getSupportsCarrierDetect", nm_dbus_device_get_supports_carrier_detect); + nm_dbus_method_list_add_method (list, "getName", nm_dbus_device_get_name); + nm_dbus_method_list_add_method (list, "getType", nm_dbus_device_get_type); + nm_dbus_method_list_add_method (list, "getHalUdi", nm_dbus_device_get_hal_udi); + nm_dbus_method_list_add_method (list, "getIP4Address", nm_dbus_device_get_ip4_address); + nm_dbus_method_list_add_method (list, "getHWAddress", nm_dbus_device_get_hw_address); + nm_dbus_method_list_add_method (list, "getMode", nm_dbus_device_get_mode); + nm_dbus_method_list_add_method (list, "getStrength", nm_dbus_device_get_strength); + nm_dbus_method_list_add_method (list, "getActiveNetwork", nm_dbus_device_get_active_network); + nm_dbus_method_list_add_method (list, "getNetworks", nm_dbus_device_get_networks); + nm_dbus_method_list_add_method (list, "getLinkActive", nm_dbus_device_get_link_active); + nm_dbus_method_list_add_method (list, "setLinkActive", nm_dbus_device_set_link_active); + nm_dbus_method_list_add_method (list, "getDriverSupportLevel", nm_dbus_device_get_driver_support_level); return (list); } diff --git a/src/nm-dbus-nm.c b/src/nm-dbus-nm.c index 55061cc305..fce172b645 100644 --- a/src/nm-dbus-nm.c +++ b/src/nm-dbus-nm.c @@ -123,7 +123,10 @@ static DBusMessage *nm_dbus_nm_get_devices (DBusConnection *connection, DBusMess * (something which should never happen), die. */ if (!appended) - g_assert ("Device list existed, but no devices were in it."); + { + syslog (LOG_ERR, "Device list existed, but no devices were in it.\n"); + g_assert_not_reached (); + } nm_unlock_mutex (data->data->dev_list_mutex, __FUNCTION__); } @@ -413,7 +416,19 @@ static DBusMessage * nm_dbus_nm_set_user_key_for_network (DBusConnection *connec } -static DBusMessage *nm_dbus_nm_set_scanning_enabled (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +static DBusMessage *nm_dbus_nm_get_wireless_scan_method (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + DBusMessage *reply = NULL; + + g_return_val_if_fail (data && data->data && connection && message, NULL); + + if ((reply = dbus_message_new_method_return (message))) + dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, data->data->scanning_method, DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage *nm_dbus_nm_set_wireless_enabled (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) { gboolean enabled = FALSE; DBusError err; @@ -422,50 +437,85 @@ static DBusMessage *nm_dbus_nm_set_scanning_enabled (DBusConnection *connection, dbus_error_init (&err); if (dbus_message_get_args (message, &err, DBUS_TYPE_BOOLEAN, &enabled, DBUS_TYPE_INVALID)) - data->data->scanning_enabled = enabled; + { + GSList *elt; + NMData *app_data; + + app_data = data->data; + app_data->wireless_enabled = enabled; + + /* Physically down all wireless devices */ + nm_lock_mutex (app_data->dev_list_mutex, __FUNCTION__); + for (elt = app_data->dev_list; elt; elt = g_slist_next (elt)) + { + NMDevice *dev = (NMDevice *)(elt->data); + if (nm_device_is_wireless (dev)) + { + nm_device_deactivate (dev, FALSE); + nm_device_bring_down (dev); + } + } + nm_unlock_mutex (app_data->dev_list_mutex, __FUNCTION__); + nm_policy_schedule_state_update (app_data); + } return NULL; } -static DBusMessage *nm_dbus_nm_get_scanning_enabled (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +static DBusMessage *nm_dbus_nm_get_wireless_enabled (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) { DBusMessage *reply = NULL; g_return_val_if_fail (data && data->data && connection && message, NULL); if ((reply = dbus_message_new_method_return (message))) - dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, data->data->scanning_enabled, DBUS_TYPE_INVALID); - + dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, data->data->wireless_enabled, DBUS_TYPE_INVALID); + return reply; } -static DBusMessage *nm_dbus_nm_set_wireless_enabled (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +static DBusMessage *nm_dbus_nm_sleep (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) { - gboolean enabled = FALSE; - DBusError err; + GSList *elt; + NMData *app_data; g_return_val_if_fail (data && data->data && connection && message, NULL); - dbus_error_init (&err); - if (dbus_message_get_args (message, &err, DBUS_TYPE_BOOLEAN, &enabled, DBUS_TYPE_INVALID)) + app_data = data->data; + if (app_data->asleep == FALSE) { - data->data->wireless_enabled = enabled; - nm_policy_schedule_state_update (data->data); + app_data->asleep = TRUE; + + /* Physically down all devices */ + nm_lock_mutex (app_data->dev_list_mutex, __FUNCTION__); + for (elt = app_data->dev_list; elt; elt = g_slist_next (elt)) + { + NMDevice *dev = (NMDevice *)(elt->data); + + nm_device_deactivate (dev, FALSE); + nm_device_bring_down (dev); + } + nm_unlock_mutex (app_data->dev_list_mutex, __FUNCTION__); + nm_policy_schedule_state_update (app_data); } return NULL; } -static DBusMessage *nm_dbus_nm_get_wireless_enabled (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +static DBusMessage *nm_dbus_nm_wake (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) { - DBusMessage *reply = NULL; + NMData *app_data; g_return_val_if_fail (data && data->data && connection && message, NULL); - if ((reply = dbus_message_new_method_return (message))) - dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, data->data->wireless_enabled, DBUS_TYPE_INVALID); + app_data = data->data; + if (app_data->asleep == TRUE) + { + app_data->asleep = FALSE; + nm_policy_schedule_state_update (app_data); + } - return reply; + return NULL; } static DBusMessage *nm_dbus_nm_get_status (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) @@ -499,10 +549,11 @@ NMDbusMethodList *nm_dbus_nm_methods_setup (void) nm_dbus_method_list_add_method (list, "setActiveDevice", nm_dbus_nm_set_active_device); nm_dbus_method_list_add_method (list, "createWirelessNetwork", nm_dbus_nm_create_wireless_network); nm_dbus_method_list_add_method (list, "setKeyForNetwork", nm_dbus_nm_set_user_key_for_network); - nm_dbus_method_list_add_method (list, "setScanningEnabled", nm_dbus_nm_set_scanning_enabled); - nm_dbus_method_list_add_method (list, "getScanningEnabled", nm_dbus_nm_get_scanning_enabled); + nm_dbus_method_list_add_method (list, "getWirelessScanMethod", nm_dbus_nm_get_wireless_scan_method); nm_dbus_method_list_add_method (list, "setWirelessEnabled", nm_dbus_nm_set_wireless_enabled); nm_dbus_method_list_add_method (list, "getWirelessEnabled", nm_dbus_nm_get_wireless_enabled); + nm_dbus_method_list_add_method (list, "sleep", nm_dbus_nm_sleep); + nm_dbus_method_list_add_method (list, "wake", nm_dbus_nm_wake); nm_dbus_method_list_add_method (list, "status", nm_dbus_nm_get_status); nm_dbus_method_list_add_method (list, "createTestDevice", nm_dbus_nm_create_test_device); nm_dbus_method_list_add_method (list, "removeTestDevice", nm_dbus_nm_remove_test_device); |