diff --git a/ChangeLog b/ChangeLog index e0d5499b51..2e3a2e7e84 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,61 @@ +2004-07-15 Dan Williams + + * src/Makefile.am + - Turn on warnings + + * src/NetworkManager.c + - nm_create_device_and_add_to_list(): call nm_device_deactivate() rather + that doing the deactivation ourselves + - Cancel an pending actions on a device if its being removed + - Break up link state checking a bit, make non-active wireless cards + deactivated to save power + - Remove unused variables + + * src/NetworkManager.h + - Add support for "pending" device + + * src/NetworkManagerAP.h + src/NetworkManagerAP.c + - Add support for determining whether and AP has encryption enabled or not + - AP address is now "struct ether_addr" rather than a string + + * src/NetworkManagerDbus.h + src/NetworkManagerDbus.c + - Add signal NeedKeyForNetwork, method SetKeyForNetwork (testing only) + - Changes for AP address from struct ether_addr->string + + * src/NetworkManagerDevice.h + src/NetworkManagerDevice.c + - Remove unused variables, fix warnings + - Add support for Pending Actions (things that block a device from being "active" + until they are completed). + - First pending action: Get a WEP key from the user + - Add nm_device_is_wire[d|less](), rename nm_device_is_wireless() + - Clean up explicit testing of dev->iface_type to use nm_device_is_wireless() + - Update wireless link checking to try to determine if the AP we are associated + with is correct, but the WEP key we are using is just wrong. If its wrong, + trigger the GetUserKey pending action on the device + - If dhclient can't get an IP address, it brings the device down. Bring it back + up in that case, otherwise we can't scan or link-check on it + - Add IP address change notifications at appropriate points (still needs some work) + - Add nm_device_need_ap_switch(), checks whether we need to switch access points or not + + * src/NetworkManagerPolicy.h + src/NetworkManagerPolicy.c + - Split out "best" access point determiniation into separate function + - Make device activation 2-stage: first the device is pending, then + in the next iteration through it becomes "active" unless it has + pending actions + + * src/NetworkManagerUtils.h + src/NetworkManagerUtils.c + - Clean up unused variables and warnings + - Wrap our debug macros in {} to prevent possible confusion + + * src/NetworkManagerWireless.c + - Forgot to return current best priority, which lead to last available AP always + being chosen no matter what its priority was. Corrected. + 2004-07-15 Dan Williams * dispatcher-daemon/Makefile.am diff --git a/src/Makefile.am b/src/Makefile.am index 53c50b84bf..4081c35174 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,10 @@ EXTRA_DIST = NetworkManager.conf -INCLUDES = \ - $(NM_CFLAGS) \ - -DDBUS_API_SUBJECT_TO_CHANGE \ - -DBINDIR=\"$(bindir)\" \ +INCLUDES = \ + $(NM_CFLAGS) \ + -Wall \ + -DDBUS_API_SUBJECT_TO_CHANGE \ + -DBINDIR=\"$(bindir)\" \ -DDATADIR=\"$(datadir)\" bin_PROGRAMS = NetworkManager diff --git a/src/Makefile.in b/src/Makefile.in index c6253ad603..cfcaa67712 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -56,6 +56,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +GLADE_CFLAGS = @GLADE_CFLAGS@ +GLADE_LIBS = @GLADE_LIBS@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -110,9 +112,10 @@ target_alias = @target_alias@ EXTRA_DIST = NetworkManager.conf INCLUDES = \ - $(NM_CFLAGS) \ - -DDBUS_API_SUBJECT_TO_CHANGE \ - -DBINDIR=\"$(bindir)\" \ + $(NM_CFLAGS) \ + -Wall \ + -DDBUS_API_SUBJECT_TO_CHANGE \ + -DBINDIR=\"$(bindir)\" \ -DDATADIR=\"$(datadir)\" diff --git a/src/NetworkManager.c b/src/NetworkManager.c index ac0963b17e..c17147be49 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -90,56 +90,28 @@ NMDevice * nm_create_device_and_add_to_list (NMData *data, const char *udi) */ if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__)) { - unsigned char buf[500]; - NM_DEBUG_PRINT_3( "nm_create_device_and_add_to_list() adding udi='%s', iface='%s', iface_type=%s\n", nm_device_get_udi (dev), nm_device_get_iface (dev), nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET ? "wireless" : "wired" ); data->dev_list = g_slist_append (data->dev_list, dev); - - /* Initialize and bring up all new devices */ - if (nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET) - { - /* Disable WEP, take device down */ - nm_device_bring_down (dev); - nm_device_set_wep_key (dev, NULL); - nm_device_set_essid (dev, NULL); - } - else - { - if (!nm_device_is_up (dev)) - nm_device_bring_up (dev); - } - - /* Remove routing table entries */ - snprintf (buf, 500, "/sbin/ip route flush dev %s", nm_device_get_iface (dev)); - system (buf); - - /* Remove ip address */ - snprintf (buf, 500, "/sbin/ip address flush dev %s", nm_device_get_iface (dev)); - system (buf); - + nm_device_deactivate (dev, TRUE); success = TRUE; nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); - } - else - NM_DEBUG_PRINT( "nm_create_device_and_add_to_list() could not acquire device list mutex.\n" ); - } - else - NM_DEBUG_PRINT( "nm_create_device_and_add_to_list() could not allocate device data.\n" ); + } else NM_DEBUG_PRINT( "nm_create_device_and_add_to_list() could not acquire device list mutex.\n" ); + } else NM_DEBUG_PRINT( "nm_create_device_and_add_to_list() could not allocate device data.\n" ); hal_free_string (iface_name); - if (!success) + if (success) + nm_data_set_state_modified (data, TRUE); + else { /* If we couldn't add the device to our list, free its data. */ nm_device_unref (dev); dev = NULL; } - } - else - NM_DEBUG_PRINT_1( "nm_create_device_and_add_to_list(): device %s does not have 'net.interface' property\n", udi ); + } else NM_DEBUG_PRINT_1( "nm_create_device_and_add_to_list(): device %s does not have 'net.interface' property\n", udi ); return (dev); } @@ -173,29 +145,27 @@ void nm_remove_device_from_list (NMData *data, const char *udi) { if (nm_null_safe_strcmp (nm_device_get_udi (dev), udi) == 0) { - if ( data->active_device - && (dev == data->active_device)) - { - nm_device_unref (data->active_device); + if (data->active_device && (dev == data->active_device)) data->active_device = NULL; - } + else if (data->pending_device && (dev == data->pending_device)) + data->pending_device = NULL; + + nm_device_pending_action_cancel (dev); + 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, element); nm_device_unref (element->data); g_slist_free (element); - + nm_data_set_state_modified (data, TRUE); + break; } } - element = g_slist_next (element); } - nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); - } - else - NM_DEBUG_PRINT( "nm_remove_device_from_list() could not acquire device list mutex.\n" ); + } else NM_DEBUG_PRINT( "nm_remove_device_from_list() could not acquire device list mutex.\n" ); } @@ -333,40 +303,47 @@ gboolean nm_link_state_monitor (gpointer user_data) if (dev) { - if ( dev != data->active_device - && (nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET)) - { - /* If its a wireless card, make sure its down. Saves power. */ - if (nm_device_is_up (dev)) - nm_device_bring_down (dev); - } - - if ((nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRED_ETHERNET)) - { - /* Make sure the device is up first. It doesn't have to have - * an IP address or anything, but most wired devices cannot do link - * detection when they are down. - */ - if (!nm_device_is_up (dev)) - nm_device_bring_up (dev); - - nm_device_update_link_active (dev, FALSE); - } - - /* Check if the device's IP address has changed - * (ie dhcp lease renew/address change) + /* Wired cards are always up and active, because otherwise we cannot do + * link detection on them. A wireless card is only up if it's the active + * device, since we only do scanning and link detection on the active device + * anyway. */ + switch (nm_device_get_iface_type (dev)) + { + case NM_IFACE_TYPE_WIRELESS_ETHERNET: + if (dev != data->active_device) + { + if (nm_device_is_up (dev)) + nm_device_bring_down (dev); + } + else + nm_device_update_link_active (dev, FALSE); + break; + + case NM_IFACE_TYPE_WIRED_ETHERNET: + if (!nm_device_is_up (dev)) + nm_device_bring_up (dev); + nm_device_update_link_active (dev, FALSE); + break; + + default: + break; + } + if (dev == data->active_device) + { + /* Check if the device's IP address has changed + * (ie dhcp lease renew/address change) + */ nm_device_update_ip4_address (dev); + } } element = g_slist_next (element); } nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); - } - else - NM_DEBUG_PRINT( "nm_link_state_monitor() could not acquire device list mutex.\n" ); + } else NM_DEBUG_PRINT( "nm_link_state_monitor() could not acquire device list mutex.\n" ); return (TRUE); } @@ -496,6 +473,7 @@ static void nm_data_free (NMData *data) g_slist_free (data->dev_list); g_mutex_free (data->dev_list_mutex); nm_device_unref (data->active_device); + nm_device_unref (data->pending_device); nm_data_allowed_ap_list_free (data); } @@ -613,7 +591,6 @@ int main( int argc, char *argv[] ) if (become_daemon) { int child_pid; - int dev_null_fd; if (chdir ("/") < 0) { diff --git a/src/NetworkManager.h b/src/NetworkManager.h index 33868e527e..984cf626dd 100644 --- a/src/NetworkManager.h +++ b/src/NetworkManager.h @@ -33,6 +33,7 @@ struct NMData GSList *dev_list; GMutex *dev_list_mutex; struct NMDevice *active_device; + struct NMDevice *pending_device; gboolean state_modified; GMutex *state_modified_mutex; GSList *allowed_ap_list; diff --git a/src/NetworkManagerAP.c b/src/NetworkManagerAP.c index ef4b7224a6..e8f37f997c 100644 --- a/src/NetworkManagerAP.c +++ b/src/NetworkManagerAP.c @@ -30,17 +30,18 @@ extern gboolean debug; */ struct NMAccessPoint { - guint refcount; - gchar *essid; - gchar *address; - guint8 quality; - double freq; - guint16 rate; - time_t stamp; + guint refcount; + gchar *essid; + struct ether_addr *address; + guint8 quality; + double freq; + guint16 rate; + time_t stamp; + gboolean encrypted; /* Things from user prefs */ - gchar *wep_key; - guint priority; + gchar *wep_key; + guint priority; }; @@ -56,7 +57,7 @@ NMAccessPoint * nm_ap_new (void) ap = g_new0 (NMAccessPoint, 1); if (!ap) - NM_DEBUG_PRINT( "nm_ap_new() could not allocate a new user access point info structure. Not enough memory?" ); + NM_DEBUG_PRINT( "nm_ap_new() could not allocate a new user access point info structure. Not enough memory?" ) ap->priority = NM_AP_PRIORITY_WORST; ap->refcount = 1; @@ -73,23 +74,31 @@ NMAccessPoint * nm_ap_new (void) */ NMAccessPoint * nm_ap_new_from_ap (NMAccessPoint *src_ap) { - NMAccessPoint *new_ap; + NMAccessPoint *new_ap; + struct ether_addr *new_addr; g_return_val_if_fail (src_ap != NULL, NULL); + new_addr = g_new0 (struct ether_addr, 1); + g_return_val_if_fail (new_addr != NULL, NULL); + new_ap = nm_ap_new(); if (!new_ap) - NM_DEBUG_PRINT( "nm_ap_new_from_uap() could not allocate a new user access point info structure. Not enough memory?" ); + NM_DEBUG_PRINT( "nm_ap_new_from_uap() could not allocate a new user access point info structure. Not enough memory?" ) new_ap->refcount = 1; if (src_ap->essid && (strlen (src_ap->essid) > 0)) new_ap->essid = g_strdup (src_ap->essid); - if (src_ap->address && (strlen (src_ap->address) > 0)) - new_ap->address = g_strdup (src_ap->address); + if (src_ap->address) + { + memcpy (new_addr, src_ap->address, sizeof (struct ether_addr)); + new_ap->address = new_addr; + } new_ap->quality = src_ap->quality; new_ap->freq = src_ap->freq; new_ap->rate = src_ap->rate; + new_ap->encrypted = new_ap->encrypted; if (src_ap->wep_key && (strlen (src_ap->wep_key) > 0)) new_ap->wep_key = g_strdup (src_ap->wep_key); @@ -191,25 +200,50 @@ void nm_ap_set_wep_key (NMAccessPoint *ap, gchar * wep_key) } +/* + * Get/set functions for encrypted flag + * + */ +gboolean nm_ap_get_encrypted (NMAccessPoint *ap) +{ + g_return_val_if_fail (ap != NULL, FALSE); + + return (ap->encrypted); +} + +void nm_ap_set_encrypted (NMAccessPoint *ap, gboolean encrypted) +{ + g_return_if_fail (ap != NULL); + + ap->encrypted = encrypted; +} + + /* * Get/set functions for address * */ -gchar * nm_ap_get_address (NMAccessPoint *ap) +struct ether_addr * nm_ap_get_address (NMAccessPoint *ap) { g_return_val_if_fail (ap != NULL, NULL); return (ap->address); } -void nm_ap_set_address (NMAccessPoint *ap, gchar * address) +void nm_ap_set_address (NMAccessPoint *ap, const struct ether_addr * addr) { + struct ether_addr *new_addr; + g_return_if_fail (ap != NULL); + new_addr = g_new0 (struct ether_addr, 1); + g_return_if_fail (new_addr != NULL); + if (ap->address) g_free (ap->address); - ap->address = g_strdup (address); + memcpy (new_addr, addr, sizeof (struct ether_addr)); + ap->address = new_addr; } diff --git a/src/NetworkManagerAP.h b/src/NetworkManagerAP.h index df44c5082b..3b6f8344af 100644 --- a/src/NetworkManagerAP.h +++ b/src/NetworkManagerAP.h @@ -45,8 +45,11 @@ void nm_ap_set_essid (NMAccessPoint *ap, gchar * essid); gchar * nm_ap_get_wep_key (NMAccessPoint *ap); void nm_ap_set_wep_key (NMAccessPoint *ap, gchar * wep_key); -gchar * nm_ap_get_address (NMAccessPoint *ap); -void nm_ap_set_address (NMAccessPoint *ap, gchar * address); +gboolean nm_ap_get_encrypted (NMAccessPoint *ap); +void nm_ap_set_encrypted (NMAccessPoint *ap, gboolean encrypted); + +struct ether_addr * nm_ap_get_address (NMAccessPoint *ap); +void nm_ap_set_address (NMAccessPoint *ap, const struct ether_addr *addr); guint8 nm_ap_get_quality (NMAccessPoint *ap); void nm_ap_set_quality (NMAccessPoint *ap, guint8 quality); diff --git a/src/NetworkManagerDbus.c b/src/NetworkManagerDbus.c index 5d2e71074f..0ec5a251f9 100644 --- a/src/NetworkManagerDbus.c +++ b/src/NetworkManagerDbus.c @@ -22,6 +22,7 @@ #include #include #include +#include extern gboolean debug; @@ -156,14 +157,13 @@ NMDevice *nm_dbus_get_device_from_object_path (const char *path, int *dev_index) /* - * nm_dbus_get_network_by_object_path + * nm_dbus_get_network_from_object_path * * Returns the network (ap) associated with a dbus object path * */ -NMAccessPoint *nm_dbus_get_network_by_object_path (const char *path, NMDevice *dev, int dev_index, int *ap_index) +NMAccessPoint *nm_dbus_get_network_from_object_path (const char *path, NMDevice *dev, int dev_index, int *ap_index) { - NMData *data; NMAccessPoint *ap = NULL; int i = 0; char compare_path[100]; @@ -172,7 +172,7 @@ NMAccessPoint *nm_dbus_get_network_by_object_path (const char *path, NMDevice *d g_return_val_if_fail (path != NULL, NULL); - while (ap = nm_device_ap_list_get_ap (dev, i)) + while ((ap = nm_device_ap_list_get_ap (dev, i)) != NULL) { snprintf (compare_path, 100, "%s/%d/Networks/%d", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, dev_index, i); if (strncmp (path, compare_path, strlen (compare_path)) == 0) @@ -413,6 +413,49 @@ void nm_dbus_signal_device_now_active (DBusConnection *connection, NMDevice *dev } +/* + * nm_dbus_signal_need_key_for_network + * + * Notifies the bus that NetworkManager needs a encryption key for a particular access point, + * because it does not have one or the one stored with allowed access points is wrong. + * + * Returns: 0 on no error + * -1 on error + */ +int nm_dbus_signal_need_key_for_network (DBusConnection *connection, NMDevice *dev, NMAccessPoint *ap) +{ + DBusMessage *message; + unsigned char *object_path = g_new0 (unsigned char, 100); + int return_val = -1; + + g_return_val_if_fail (dev != NULL, -1); + g_return_val_if_fail (ap != NULL, -1); + g_return_val_if_fail (nm_ap_get_essid (ap) != NULL, -1); + + message = dbus_message_new_signal (NM_DBUS_NM_OBJECT_PATH_PREFIX, NM_DBUS_NM_NAMESPACE, "NeedKeyForNetwork"); + if (!message) + { + NM_DEBUG_PRINT ("nm_dbus_signal_need_wep_key_for_network(): Not enough memory for new dbus message!\n"); + return (return_val); + } + + nm_dbus_get_object_path_from_device (dev, object_path, 100, FALSE); + dbus_message_append_args (message, DBUS_TYPE_STRING, object_path, DBUS_TYPE_INVALID); + dbus_message_append_args (message, DBUS_TYPE_STRING, nm_ap_get_essid (ap), DBUS_TYPE_INVALID); + g_free (object_path); + + if (!dbus_connection_send (connection, message, NULL)) + { + NM_DEBUG_PRINT ("nm_dbus_signal_need_wep_key_for_network(): Could not raise the NeedKeyForNetwork signal!\n"); + } + else + return_val = 0; + + dbus_message_unref (message); + return (return_val); +} + + /* * nm_dbus_signal_device_ip4_address_change * @@ -456,7 +499,7 @@ static DBusMessage *nm_dbus_devices_handle_networks_request (DBusConnection *con DBusMessageIter iter; int ap_index; - ap = nm_dbus_get_network_by_object_path (path, dev, dev_index, &ap_index); + ap = nm_dbus_get_network_from_object_path (path, dev, dev_index, &ap_index); if (!ap || (ap_index == -1)) { reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "NetworkNotFound", @@ -470,7 +513,13 @@ static DBusMessage *nm_dbus_devices_handle_networks_request (DBusConnection *con if (strcmp ("getName", request) == 0) dbus_message_iter_append_string (&iter, nm_ap_get_essid (ap)); else if (strcmp ("getAddress", request) == 0) - dbus_message_iter_append_string (&iter, nm_ap_get_address (ap)); + { + char buf[20]; + + memset (&buf[0], 0, 20); + iw_ether_ntop((const struct ether_addr *) (nm_ap_get_address (ap)), &buf[0]); + dbus_message_iter_append_string (&iter, &buf[0]); + } else if (strcmp ("getQuality", request) == 0) dbus_message_iter_append_int32 (&iter, nm_ap_get_quality (ap)); else if (strcmp ("getFrequency", request) == 0) @@ -533,12 +582,30 @@ static DBusMessage *nm_dbus_devices_handle_request (DBusConnection *connection, dbus_message_iter_append_int32 (&iter, nm_device_get_iface_type (dev)); else if (strcmp ("getIP4Address", request) == 0) dbus_message_iter_append_uint32 (&iter, nm_device_get_ip4_address (dev)); + else if (strcmp ("setKeyForNetwork", request) == 0) + { + DBusMessageIter key_iter; + char *dbus_string; + char *key; + + dbus_message_iter_init (message, &key_iter); + dbus_string = dbus_message_iter_get_string (&key_iter); + key = (dbus_string == NULL ? NULL : strdup (dbus_string)); + dbus_free (dbus_string); + + if (!key) + { + NM_DEBUG_PRINT ("NetworkManagerClient returned a NULL key in setKeyForNetwork message" ) + } + else + nm_device_pending_action_set_user_key (dev, key); + } else if (strcmp ("getActiveNetwork", request) == 0) { NMAccessPoint *ap = NULL; int i = 0; - while (ap = nm_device_ap_list_get_ap (dev, i)) + while ((ap = nm_device_ap_list_get_ap (dev, i)) != NULL) { if (nm_null_safe_strcmp (nm_ap_get_essid (ap), nm_device_get_essid (dev)) == 0) { @@ -563,7 +630,7 @@ static DBusMessage *nm_dbus_devices_handle_request (DBusConnection *connection, dbus_message_iter_append_array (&iter, &iter_array, DBUS_TYPE_STRING); - while (ap = nm_device_ap_list_get_ap (dev, i)) + while ((ap = nm_device_ap_list_get_ap (dev, i)) != NULL) { object_path = g_strdup_printf ("%s/%d/Networks/%d", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, dev_index, i); dbus_message_iter_append_string (&iter_array, object_path); diff --git a/src/NetworkManagerDbus.h b/src/NetworkManagerDbus.h index 7ad8dc4069..0265805549 100644 --- a/src/NetworkManagerDbus.h +++ b/src/NetworkManagerDbus.h @@ -40,4 +40,6 @@ void nm_dbus_signal_device_now_active (DBusConnection *connection, NMDevice void nm_dbus_signal_device_ip4_address_change(DBusConnection *connection, NMDevice *dev); +int nm_dbus_signal_need_key_for_network (DBusConnection *connection, NMDevice *dev, NMAccessPoint *ap); + #endif diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index 716d87c782..a4aaf833e6 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -24,23 +24,28 @@ #include #include #include +#include +#include #include "NetworkManager.h" #include "NetworkManagerDevice.h" #include "NetworkManagerUtils.h" +#include "NetworkManagerDbus.h" +#include "NetworkManagerWireless.h" +#include "NetworkManagerPolicy.h" + extern gboolean debug; static gboolean mii_get_link (NMDevice *dev); -static void nm_device_link_detection_init (NMDevice *dev); /* - * nm_device_is_wireless + * nm_device_test_wireless_extensions * * Test whether a given device is a wireless one or not. * */ -static gboolean nm_device_is_wireless (NMDevice *dev) +static gboolean nm_device_test_wireless_extensions (NMDevice *dev) { int iwlib_socket; int error; @@ -65,7 +70,6 @@ static gboolean nm_device_supports_wireless_scan (NMDevice *dev) { int iwlib_socket; int error; - iwstats stats; gboolean can_scan = TRUE; wireless_scan_head scan_data; @@ -157,6 +161,13 @@ NMDevice *nm_get_device_by_iface (NMData *data, const char *iface) /* NMDevice object routines */ /*****************************************************************************/ +enum NMPendingAction +{ + NM_PENDING_ACTION_NONE, + NM_PENDING_ACTION_GET_USER_KEY +}; +typedef enum NMPendingAction NMPendingAction; + typedef struct NMDeviceWirelessOptions { gchar *cur_essid; @@ -177,19 +188,30 @@ typedef union NMDeviceOptions NMDeviceWiredOptions wired; } NMDeviceOptions; +typedef struct NMPendingActionUserKeyOptions +{ + unsigned char *essid; // ESSID we are waiting for a key for +} NMPendingActionUserKeyOptions; + +typedef union NMPendingActionOptions +{ + NMPendingActionUserKeyOptions user_key; +} NMPendingActionOptions; /* * NetworkManager device structure */ struct NMDevice { - guint refcount; - gchar *udi; - gchar *iface; - NMIfaceType iface_type; - gboolean link_active; - guint32 ip4_address; + guint refcount; + gchar *udi; + gchar *iface; + NMIfaceType iface_type; + gboolean link_active; + NMPendingAction pending_action; + NMPendingActionOptions pending_action_options; + guint32 ip4_address; /* FIXME: ipv6 address too */ - NMDeviceOptions dev_options; + NMDeviceOptions dev_options; }; @@ -214,7 +236,7 @@ NMDevice *nm_device_new (const char *iface) dev->refcount = 1; dev->iface = g_strdup (iface); - dev->iface_type = nm_device_is_wireless (dev) ? + dev->iface_type = nm_device_test_wireless_extensions (dev) ? NM_IFACE_TYPE_WIRELESS_ETHERNET : NM_IFACE_TYPE_WIRED_ETHERNET; if (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET) @@ -316,6 +338,20 @@ guint nm_device_get_iface_type (NMDevice *dev) return (dev->iface_type); } +gboolean nm_device_is_wireless (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET); +} + +gboolean nm_device_is_wired (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return (dev->iface_type == NM_IFACE_TYPE_WIRED_ETHERNET); +} + /* * Get/set functions for link_active @@ -342,6 +378,9 @@ gboolean nm_device_get_supports_wireless_scan (NMDevice *dev) { g_return_val_if_fail (dev != NULL, FALSE); + if (!nm_device_is_wireless (dev)) + return (FALSE); + return (dev->dev_options.wireless.supports_wireless_scan); } @@ -363,7 +402,6 @@ void nm_device_update_link_active (NMDevice *dev, gboolean check_mii) * seems to be whether the card has a valid access point MAC address. * Is there a better way? */ - switch (nm_device_get_iface_type (dev)) { case NM_IFACE_TYPE_WIRELESS_ETHERNET: @@ -371,9 +409,33 @@ void nm_device_update_link_active (NMDevice *dev, gboolean check_mii) struct iwreq wrq; int iwlib_socket; + /* Update the "best" ap for the card */ + nm_device_do_wireless_scan (dev); + iwlib_socket = iw_sockets_open (); if (iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0) - link_active = nm_ethernet_address_is_valid ((struct ether_addr *)(&(wrq.u.ap_addr.sa_data))); + { + NMAccessPoint *ap = nm_device_get_best_ap (dev); + unsigned char *essid = nm_device_get_essid (dev); + + if (ap && essid && (strcmp (essid, nm_ap_get_essid (ap)) == 0)) + { +fprintf (stderr, "Best AP: '%s', current AP: '%s'\n", nm_ap_get_essid (ap), nm_device_get_essid (dev)); + /* If either: + * 1) the associated AP's MAC address is valid, or + * 2) its not valid but encryption is turned on (not valid b/c key might be wrong) + * then we consider there to be a "link" + */ + if (nm_ethernet_address_is_valid ((struct ether_addr *)(&(wrq.u.ap_addr.sa_data)))) + link_active = TRUE; + else if (nm_ap_get_encrypted (ap)) + { + link_active = TRUE; + /* Make sure we are at least attempting to get the key */ + nm_device_pending_action_get_user_key (dev, ap); + } + } + } close (iwlib_socket); break; } @@ -419,7 +481,7 @@ char * nm_device_get_essid (NMDevice *dev) char essid[IW_ESSID_MAX_SIZE + 1]; g_return_val_if_fail (dev != NULL, NULL); - g_return_val_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET, NULL); + g_return_val_if_fail (nm_device_is_wireless (dev), NULL); iwlib_socket = iw_sockets_open (); if (iwlib_socket >= 0) @@ -457,7 +519,7 @@ void nm_device_set_essid (NMDevice *dev, const char *essid) unsigned char safe_essid[IW_ESSID_MAX_SIZE + 1] = "\0"; g_return_if_fail (dev != NULL); - g_return_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET); + g_return_if_fail (nm_device_is_wireless (dev)); /* Make sure the essid we get passed is a valid size */ if (!essid) @@ -497,6 +559,7 @@ void nm_device_get_ap_address (NMDevice *dev, struct ether_addr *addr) g_return_if_fail (dev != NULL); g_return_if_fail (addr != NULL); + g_return_if_fail (nm_device_is_wireless (dev)); /* Do we have a valid MAC address? */ iwlib_socket = iw_sockets_open (); @@ -524,10 +587,8 @@ void nm_device_set_wep_key (NMDevice *dev, const char *wep_key) unsigned char safe_key[IW_ENCODING_TOKEN_MAX + 1]; gboolean set_key = FALSE; - char *it = NULL; - g_return_if_fail (dev != NULL); - g_return_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET); + g_return_if_fail (nm_device_is_wireless (dev)); /* Make sure the essid we get passed is a valid size */ if (!wep_key) @@ -583,9 +644,6 @@ void nm_device_set_wep_key (NMDevice *dev, const char *wep_key) */ guint32 nm_device_get_ip4_address(NMDevice *dev) { - struct ifreq req; - int socket; - g_return_val_if_fail (dev != NULL, 0); return (dev->ip4_address); @@ -691,8 +749,6 @@ void nm_device_bring_up (NMDevice *dev) void nm_device_bring_down (NMDevice *dev) { - int fd; - g_return_if_fail (dev != NULL); nm_device_set_up_down (dev, FALSE); @@ -704,7 +760,7 @@ gboolean nm_device_is_up (NMDevice *dev) struct ifreq ifr; int err; - g_return_if_fail (dev != NULL); + g_return_val_if_fail (dev != NULL, FALSE); iface_fd = nm_get_network_control_socket (); if (iface_fd < 0) @@ -734,7 +790,7 @@ gboolean nm_device_activate (NMDevice *dev) unsigned char buf[500]; gboolean success = FALSE; unsigned char *iface; - unsigned char hostname[500] = "\0"; + unsigned char hostname[100] = "\0"; int host_err; NMData *data = nm_get_global_data (); int dhclient_err; @@ -744,7 +800,7 @@ gboolean nm_device_activate (NMDevice *dev) g_return_val_if_fail (data != NULL, FALSE); /* If its a wireless device, set the ESSID and WEP key */ - if (nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET) + if (nm_device_is_wireless (dev)) { NMAccessPoint *ap = nm_device_get_best_ap (dev); @@ -756,7 +812,7 @@ gboolean nm_device_activate (NMDevice *dev) } /* If there is a desired AP to connect to, use that essid and possible WEP key */ - if (ap && nm_ap_get_essid (ap) != NULL) + if (ap && nm_ap_get_essid (ap)) { nm_device_bring_down (dev); @@ -766,9 +822,9 @@ gboolean nm_device_activate (NMDevice *dev) nm_device_set_wep_key (dev, NULL); if (nm_ap_get_wep_key (ap)) nm_device_set_wep_key (dev, nm_ap_get_wep_key (ap)); - } else NM_DEBUG_PRINT_1 ("nm_device_activate(%s) could not get best ap even after scan\n", nm_device_get_iface (dev)); - NM_DEBUG_PRINT_2 ("nm_device_activate(%s) using essid '%s'\n", nm_device_get_iface (dev), nm_ap_get_essid (ap)); + NM_DEBUG_PRINT_2 ("nm_device_activate(%s) using essid '%s'\n", nm_device_get_iface (dev), nm_ap_get_essid (ap)); + } } /* Bring the device up */ @@ -799,37 +855,52 @@ gboolean nm_device_activate (NMDevice *dev) kill (n_pid, 9); } - snprintf (buf, 500, "/sbin/dhclient -1 -q -lf /var/lib/dhcp/dhclient-%s.leases -pf /var/run/dhclient-%s.pid -cf /etc/dhclient-%s.conf %s\n", - iface, iface, iface, iface); - dhclient_err = system (buf); - if (dhclient_err != 0) + /* If we don't have a "best" ap, don't try to get a DHCP address or restart the name service cache */ + if (nm_device_is_wired (dev) || (nm_device_is_wireless (dev) && nm_device_get_best_ap (dev))) { - /* Interfaces cannot be down if they are the active interface, - * otherwise we cannot use them for scanning or link detection. - * If dhclient doesn't get a DHCP address, it will take the interface - * down, so we reactivate it here. + /* Save machine host name */ + host_err = gethostname (&hostname[0], 100); + + /* Unfortunately, dhclient can take a long time to get a dhcp address + * (for example, bad WEP key so it can't actually talk to the AP). + * We are essentially blocked until it returns. + * FIXME: fork() NetworkManager to do the dhclient stuff, and if our + * state changes during the dhclient stuff, we can kill() the + * forked process running dhclient. */ - if (nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET) + snprintf (buf, 500, "/sbin/dhclient -1 -q -lf /var/lib/dhcp/dhclient-%s.leases -pf /var/run/dhclient-%s.pid -cf /etc/dhclient-%s.conf %s\n", + iface, iface, iface, iface); + dhclient_err = system (buf); + if (dhclient_err != 0) { - nm_device_set_essid (dev, ""); - nm_device_set_wep_key (dev, NULL); + /* Interfaces cannot be down if they are the active interface, + * otherwise we cannot use them for scanning or link detection. + * If dhclient doesn't get a DHCP address, it will take the interface + * down, so we reactivate it here. + */ + if (nm_device_is_wireless (dev)) + { + nm_device_set_essid (dev, ""); + nm_device_set_wep_key (dev, NULL); + } + + nm_device_bring_up (dev); + success = FALSE; } - nm_device_bring_up (dev); - success = FALSE; + /* Set the hostname back to what it was before so that X11 doesn't + * puke when the hostname changes, and so users can actually launch stuff. + */ + if (host_err >= 0) + sethostname (hostname, strlen (hostname)); + + /* Restart the nameservice caching daemon to make apps aware of new DNS servers */ + snprintf (buf, 500, "/sbin/service nscd restart"); + system (buf); } - /* Set the hostname back to what it was before so that X11 doesn't - * puke when the hostname changes, and so users can actually launch stuff. - */ - if (host_err >= 0) - sethostname (hostname, strlen (hostname)); - - /* Restart the nameservice caching daemon to make apps aware of new DNS servers */ - snprintf (buf, 500, "/sbin/service nscd restart"); - system (buf); - nm_dbus_signal_device_now_active (data->dbus_connection, dev); + nm_device_update_ip4_address (dev); return (success); } @@ -841,7 +912,7 @@ gboolean nm_device_activate (NMDevice *dev) * Remove a device's routing table entries and IP address. * */ -gboolean nm_device_deactivate (NMDevice *dev) +gboolean nm_device_deactivate (NMDevice *dev, gboolean just_added) { unsigned char buf[500]; unsigned char *iface; @@ -866,17 +937,20 @@ gboolean nm_device_deactivate (NMDevice *dev) snprintf (buf, 500, "/sbin/ip address flush dev %s", iface); system (buf); + nm_device_pending_action_cancel (dev); + dev->ip4_address = 0; + success = TRUE; } - nm_dbus_signal_device_no_longer_active (data->dbus_connection, dev); + if (!just_added) + nm_dbus_signal_device_no_longer_active (data->dbus_connection, dev); /* Clean up stuff, don't leave the card associated or up */ - if (nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET) + if (nm_device_is_wireless (dev)) { nm_device_set_essid (dev, ""); nm_device_set_wep_key (dev, NULL); - nm_device_bring_down (dev); } @@ -884,6 +958,70 @@ gboolean nm_device_deactivate (NMDevice *dev) } +gboolean nm_device_pending_action (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return (dev->pending_action != NM_PENDING_ACTION_NONE); +} + +void nm_device_pending_action_get_user_key (NMDevice *dev, NMAccessPoint *ap) +{ + NMData *data = nm_get_global_data (); + + g_return_if_fail (data != NULL); + g_return_if_fail (dev != NULL); + g_return_if_fail (nm_device_is_wireless (dev)); + g_return_if_fail (ap != NULL); + g_return_if_fail (nm_ap_get_essid (ap) != NULL); + + if (dev->pending_action != NM_PENDING_ACTION_NONE) + return; + + if (nm_dbus_signal_need_key_for_network (data->dbus_connection, dev, ap) == 0) + { + dev->pending_action = NM_PENDING_ACTION_GET_USER_KEY; + dev->pending_action_options.user_key.essid = g_strdup (nm_ap_get_essid (ap)); + } +} + +void nm_device_pending_action_set_user_key (NMDevice *dev, unsigned char *key) +{ + g_return_if_fail (dev != NULL); + g_return_if_fail (nm_device_is_wireless (dev)); + g_return_if_fail (dev->pending_action == NM_PENDING_ACTION_GET_USER_KEY); + g_return_if_fail (key != NULL); + + /* We only set the key on the access point if we can verify that the key is meant + * for that access point. + */ + if(dev->pending_action_options.user_key.essid) + { + NMAccessPoint *best_ap = nm_device_get_best_ap (dev); + + if (best_ap) + { + /* Make sure the "best" ap matches the essid we asked for the key of */ + if (nm_null_safe_strcmp (dev->pending_action_options.user_key.essid, nm_ap_get_essid (best_ap))) + nm_ap_set_wep_key (best_ap, key); + } + g_free (dev->pending_action_options.user_key.essid); + } + + dev->pending_action = NM_PENDING_ACTION_NONE; +} + +void nm_device_pending_action_cancel (NMDevice *dev) +{ + g_return_if_fail (dev != NULL); + + if ( dev->pending_action == NM_PENDING_ACTION_GET_USER_KEY + && dev->pending_action_options.user_key.essid) + g_free (dev->pending_action_options.user_key.essid); + dev->pending_action = NM_PENDING_ACTION_NONE; +} + + /* * nm_device_ap_list_add * @@ -894,7 +1032,7 @@ void nm_device_ap_list_add (NMDevice *dev, NMAccessPoint *ap) { g_return_if_fail (dev != NULL); g_return_if_fail (ap != NULL); - g_return_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET); + g_return_if_fail (nm_device_is_wireless (dev)); if (nm_try_acquire_mutex (dev->dev_options.wireless.ap_list_mutex, __FUNCTION__)) { @@ -917,7 +1055,7 @@ void nm_device_ap_list_clear (NMDevice *dev) GSList *element; g_return_if_fail (dev != NULL); - g_return_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET); + g_return_if_fail (nm_device_is_wireless (dev)); if (!dev->dev_options.wireless.ap_list) return; @@ -947,7 +1085,7 @@ void nm_device_ap_list_clear (NMDevice *dev) /* * nm_device_ap_list_get_ap * - * Copy the list of ESSIDs + * Get the access point at a specified index in the list * */ NMAccessPoint *nm_device_ap_list_get_ap (NMDevice *dev, int index) @@ -956,10 +1094,10 @@ NMAccessPoint *nm_device_ap_list_get_ap (NMDevice *dev, int index) NMAccessPoint *ap = NULL; g_return_val_if_fail (dev != NULL, NULL); - g_return_val_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET, NULL); + g_return_val_if_fail (nm_device_is_wireless (dev), NULL); if (!dev->dev_options.wireless.ap_list) - return; + return (NULL); if (nm_try_acquire_mutex (dev->dev_options.wireless.ap_list_mutex, __FUNCTION__)) { @@ -991,7 +1129,7 @@ NMAccessPoint *nm_device_ap_list_get_ap (NMDevice *dev, int index) NMAccessPoint *nm_device_get_best_ap (NMDevice *dev) { g_return_val_if_fail (dev != NULL, NULL); - g_return_val_if_fail (nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET, NULL); + g_return_val_if_fail (nm_device_is_wireless (dev), NULL); return (dev->dev_options.wireless.best_ap); } @@ -1000,15 +1138,31 @@ void nm_device_set_best_ap (NMDevice *dev, NMAccessPoint *ap) { g_return_if_fail (dev != NULL); g_return_if_fail (ap != NULL); - g_return_if_fail (nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET); + g_return_if_fail (nm_device_is_wireless (dev)); if (dev->dev_options.wireless.best_ap) nm_ap_unref (dev->dev_options.wireless.best_ap); - nm_ap_ref (ap); - dev->dev_options.wireless.best_ap = ap; + /* We create a _copy_ of the AP, because we may need to get a WEP + * key from the user later and we set it on the AP. + */ + dev->dev_options.wireless.best_ap = nm_ap_new_from_ap (ap); } +gboolean nm_device_need_ap_switch (NMDevice *dev) +{ + NMAccessPoint *ap; + gboolean need_switch = FALSE; + + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (nm_device_is_wireless (dev), FALSE); + + ap = nm_device_get_best_ap (dev); + if (ap && (nm_null_safe_strcmp (nm_device_get_essid (dev), nm_ap_get_essid (ap)) != 0)) + need_switch = TRUE; + + return (need_switch); +} /* * nm_device_do_normal_scan @@ -1068,14 +1222,13 @@ static void nm_device_do_normal_scan (NMDevice *dev) /* Copy over info from scan to local structure */ nm_ap_set_essid (nm_ap, tmp_ap->b.essid); - if (tmp_ap->has_ap_addr) - { - char buf[20]; + if (tmp_ap->b.has_key && (tmp_ap->b.key_flags & IW_ENCODE_DISABLED)) + nm_ap_set_encrypted (nm_ap, FALSE); + else + nm_ap_set_encrypted (nm_ap, TRUE); - memset (&buf[0], 0, 20); - iw_ether_ntop((const struct ether_addr *) (tmp_ap->ap_addr.sa_data), &buf[0]); - nm_ap_set_address (nm_ap, buf); - } + if (tmp_ap->has_ap_addr) + nm_ap_set_address (nm_ap, (const struct ether_addr *)(tmp_ap->ap_addr.sa_data)); nm_ap_set_quality (nm_ap, tmp_ap->stats.qual.qual); @@ -1135,7 +1288,6 @@ static void nm_device_do_pseudo_scan (NMDevice *dev) nm_device_ref (dev); -fprintf (stderr, "Begining try all\n" ); /* Acquire allowed AP list mutex, silently fail if we cannot */ if (nm_try_acquire_mutex (data->allowed_ap_list_mutex, __FUNCTION__)) { @@ -1153,14 +1305,10 @@ fprintf (stderr, "Begining try all\n" ); /* Attempt to associate with this access point */ if (ap) { - struct iwreq wrq; - int iwlib_socket; gboolean valid = FALSE; struct ether_addr save_ap_addr; struct ether_addr cur_ap_addr; -fprintf( stderr, "Looking at AP %s\n", nm_ap_get_essid (ap) ); - if (!nm_device_is_up (dev)); nm_device_bring_up (dev); @@ -1179,7 +1327,6 @@ fprintf( stderr, "Looking at AP %s\n", nm_ap_get_essid (ap) ); /* 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); -fprintf( stderr, "Current ap ether is: %s save = %s\n", iw_ether_ntoa (&cur_ap_addr), iw_ether_ntoa(&save_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) @@ -1195,7 +1342,8 @@ fprintf( stderr, "Current ap ether is: %s save = %s\n", iw_ether_ntoa (&cur_ap */ if (valid) { -fprintf( stderr, "AP %s looks good, setting to desired\n", nm_ap_get_essid (ap)); + NM_DEBUG_PRINT_1 ("AP %s looks good, setting to desired\n", nm_ap_get_essid (ap)); + nm_device_set_best_ap (dev, nm_ap_new_from_ap (ap)); nm_data_set_state_modified (nm_get_global_data (), TRUE); break; @@ -1205,7 +1353,6 @@ fprintf( stderr, "AP %s looks good, setting to desired\n", nm_ap_get_essid (ap)) } nm_unlock_mutex (data->allowed_ap_list_mutex, __FUNCTION__); -fprintf( stderr, "Try all done.\n"); } nm_device_unref (dev); @@ -1224,7 +1371,7 @@ void nm_device_do_wireless_scan (NMDevice *dev) g_return_if_fail (data != NULL); g_return_if_fail (dev != NULL); - g_return_if_fail (nm_device_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET); + g_return_if_fail (nm_device_is_wireless (dev)); if (nm_device_get_supports_wireless_scan (dev)) nm_device_do_normal_scan (dev); diff --git a/src/NetworkManagerDevice.h b/src/NetworkManagerDevice.h index 2d40818c91..4af19ddb04 100644 --- a/src/NetworkManagerDevice.h +++ b/src/NetworkManagerDevice.h @@ -50,6 +50,8 @@ void nm_device_set_udi (NMDevice *dev, const char *udi); char * nm_device_get_iface (NMDevice *dev); NMIfaceType nm_device_get_iface_type (NMDevice *dev); +gboolean nm_device_is_wireless (NMDevice *dev); +gboolean nm_device_is_wired (NMDevice *dev); /* There is no nm_device_set_iface_type() because that's determined when you set the device's iface */ gboolean nm_device_get_link_active (NMDevice *dev); @@ -70,17 +72,23 @@ gboolean nm_device_get_supports_wireless_scan (NMDevice *dev); void nm_device_do_wireless_scan (NMDevice *dev); NMAccessPoint *nm_device_get_best_ap (NMDevice *dev); void nm_device_set_best_ap (NMDevice *dev, NMAccessPoint *ap); +gboolean nm_device_need_ap_switch (NMDevice *dev); /* There is no function to get the WEP key since that's a slight security risk */ void nm_device_set_wep_key (NMDevice *dev, const char *wep_key); -gboolean nm_device_deactivate (NMDevice *dev); gboolean nm_device_activate (NMDevice *dev); +gboolean nm_device_deactivate (NMDevice *dev, gboolean just_added); void nm_device_bring_up (NMDevice *dev); void nm_device_bring_down (NMDevice *dev); gboolean nm_device_is_up (NMDevice *dev); +gboolean nm_device_pending_action (NMDevice *dev); +void nm_device_pending_action_cancel (NMDevice *dev); +void nm_device_pending_action_get_user_key (NMDevice *dev, NMAccessPoint *ap); +void nm_device_pending_action_set_user_key (NMDevice *dev, unsigned char *key); + void nm_device_ap_list_add (NMDevice *dev, NMAccessPoint *ap); void nm_device_ap_list_clear (NMDevice *dev); NMAccessPoint *nm_device_ap_list_get_ap (NMDevice *dev, int index); diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index c669ae8345..d119e04591 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -37,6 +37,94 @@ gboolean allowed_ap_worker_exit = FALSE; extern gboolean debug; +/* + * nm_policy_get_best_device + * + * Filter all the devices and find the best device to use as the + * link. NOTE: caller must lock the device list if needed. + * + */ +NMDevice * nm_policy_get_best_device (NMData *data) +{ + GSList *element; + NMDevice *best_wired_dev = NULL; + guint best_wired_prio = 0; + NMDevice *best_wireless_dev = NULL; + guint best_wireless_prio = 0; + NMDevice *highest_priority_dev = NULL; + + g_return_val_if_fail (data != NULL, NULL); + element = data->dev_list; + + while (element) + { + NMDevice *dev = NULL; + guint iface_type; + gboolean link_active; + guint prio = 0; + + dev = (NMDevice *)(element->data); + + iface_type = nm_device_get_iface_type (dev); + link_active = nm_device_get_link_active (dev); + + if (iface_type == NM_IFACE_TYPE_WIRED_ETHERNET) + { + if (link_active) + prio += 1; + + if ( data->active_device + && (dev == data->active_device) + && link_active) + prio += 1; + + if (prio > best_wired_prio) + { + best_wired_dev = dev; + best_wired_prio = prio; + } + } + else if (iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET) + { + if (link_active) + prio += 1; + + if (nm_device_get_supports_wireless_scan (dev)) + prio += 2; + else + prio += 1; + + if ( data->active_device + && (dev == data->active_device) + && link_active) + prio += 3; + + if (prio > best_wireless_prio) + { + best_wireless_dev = dev; + best_wireless_prio = prio; + } + } + + element = g_slist_next (element); + } + + NM_DEBUG_PRINT_1 ("Best wired device = %s\n", best_wired_dev ? nm_device_get_iface (best_wired_dev) : "(null)"); + NM_DEBUG_PRINT_2 ("Best wireless device = %s (%s)\n", best_wireless_dev ? nm_device_get_iface (best_wireless_dev) : "(null)", + best_wireless_dev ? nm_device_get_essid (best_wireless_dev) : "null" ); + + if (best_wireless_dev || best_wired_dev) + { + if (best_wired_dev) + highest_priority_dev = best_wired_dev; + else + highest_priority_dev = best_wireless_dev; + } + + return (highest_priority_dev); +} + + /* * nm_state_modification_monitor * @@ -71,126 +159,41 @@ gboolean nm_state_modification_monitor (gpointer user_data) { if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__)) { - GSList *element = data->dev_list; - NMDevice *best_wired_dev = NULL; - guint best_wired_prio = 0; - NMDevice *best_wireless_dev = NULL; - guint best_wireless_prio = 0; - guint highest_priority = 0; - NMDevice *highest_priority_dev = NULL; - gboolean essid_change_needed = FALSE; + NMDevice *best_dev = NULL; - while (element) + if ((best_dev = nm_policy_get_best_device (data)) != NULL) + nm_device_ref (best_dev); + + /* Cancel pending device actions on an existing pending device */ + if (data->pending_device) { - NMDevice *dev = NULL; - guint iface_type; - gboolean link_active; - guint prio = 0; - - dev = (NMDevice *)(element->data); - - iface_type = nm_device_get_iface_type (dev); - link_active = nm_device_get_link_active (dev); - - if (iface_type == NM_IFACE_TYPE_WIRED_ETHERNET) - { - if (link_active) - prio += 1; - - if (data->active_device - && (dev == data->active_device) - && link_active) - prio += 1; - - if (prio > best_wired_prio) - { - best_wired_dev = dev; - best_wired_prio = prio; - } - } - else if (iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET) - { - if (link_active) - prio += 1; - - if (nm_device_get_supports_wireless_scan (dev)) - prio += 2; - - if ( data->active_device - && (dev == data->active_device) - && link_active) - prio += 3; - - if (prio > best_wireless_prio) - { - best_wireless_dev = dev; - best_wireless_prio = prio; - } - } - - element = g_slist_next (element); + nm_device_pending_action_cancel (data->pending_device); + nm_device_unref (data->pending_device); + data->pending_device = NULL; } - NM_DEBUG_PRINT_1 ("Best wired device = %s\n", best_wired_dev ? nm_device_get_iface (best_wired_dev) : "(null)"); - NM_DEBUG_PRINT_2 ("Best wireless device = %s (%s)\n", best_wireless_dev ? nm_device_get_iface (best_wireless_dev) : "(null)", - best_wireless_dev ? nm_device_get_essid (best_wireless_dev) : "null" ); - - if (best_wireless_dev || best_wired_dev) - { - if (best_wired_dev) - highest_priority_dev = best_wired_dev; - else - highest_priority_dev = best_wireless_dev; - } - else - { - /* No devices at all, wait for them to change status */ - nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); - return (TRUE); - } - - /* If the current essid of the wireless card and the desired ap's essid are different, - * trigger an interface switch. We switch to the same interface, but we still need to bring - * the device up again to get a new DHCP address. However, don't switch if there is no - * desired ap. + /* Only do a switch when: + * 1) the best_dev is different from data->active_device, OR + * 2) best_dev is wireless and its access point is not the "best" ap, OR + * 3) best_dev is wireless and its access point is the best, but it doesn't have an IP address */ - if (nm_device_get_iface_type (highest_priority_dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET) + if ( best_dev != data->active_device + || ( best_dev && nm_device_is_wireless (best_dev) + && (nm_device_need_ap_switch (best_dev) || (nm_device_get_ip4_address (best_dev) == 0)))) { - NMAccessPoint *ap = nm_device_get_best_ap (highest_priority_dev); + NM_DEBUG_PRINT_1 ("nm_state_modification_monitor() set pending_device = %s\n", best_dev ? nm_device_get_iface (best_dev) : "(null)"); - if ( ap - && (nm_null_safe_strcmp (nm_device_get_essid (highest_priority_dev), nm_ap_get_essid (ap)) != 0) - && (strlen (nm_ap_get_essid (ap)) > 0)) - essid_change_needed = TRUE; - } - - /* If the highest priority device is different than data->active_device, switch the connection. */ - if ( essid_change_needed - || (!data->active_device || (highest_priority_dev != data->active_device))) - { - NM_DEBUG_PRINT_2 ("**** Switching active interface from '%s' to '%s'\n", - data->active_device ? nm_device_get_iface (data->active_device) : "(null)", - nm_device_get_iface (highest_priority_dev)); - - /* FIXME - * We should probably wait a bit before forcibly changing connections - * after we send the signal. However, dbus delivers its messages in the - * glib main loop. If we call g_main_context_iteration(), we can deadlock - * but if we split this function into two steps and execute the second half, - * after a main loop iteration, we make a much more complicated state machine. - */ - if (data->active_device) - nm_device_deactivate (data->active_device); + data->pending_device = best_dev; + if (data->pending_device && !nm_device_is_up (data->pending_device)) + nm_device_bring_up (data->pending_device); + /* Deactivate the old device */ if (data->active_device) + { + nm_device_deactivate (data->active_device, FALSE); nm_device_unref (data->active_device); - - data->active_device = highest_priority_dev; - nm_device_ref (data->active_device); - - nm_device_activate (data->active_device); - - NM_DEBUG_PRINT ("**** Switched.\n"); + data->active_device = NULL; + } } nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); @@ -198,6 +201,20 @@ gboolean nm_state_modification_monitor (gpointer user_data) else NM_DEBUG_PRINT("nm_state_modification_monitor() could not get device list mutex\n"); } + else if (data->pending_device) + { + /* If there are pending device actions, don't switch to the device, but + * wait for the actions to complete. + */ + if (!nm_device_pending_action (data->pending_device)) + { + NM_DEBUG_PRINT_1 ("nm_state_modification_monitor() will activate device %s\n", nm_device_get_iface (data->pending_device)); + + data->active_device = data->pending_device; + data->pending_device = NULL; + nm_device_activate (data->active_device); + } + } return (TRUE); } @@ -215,7 +232,7 @@ gpointer nm_policy_allowed_ap_refresh_worker (gpointer user_data) NMData *data = (NMData *)(user_data); struct timeval timeout; - g_return_if_fail (data != NULL); + g_return_val_if_fail (data != NULL, NULL); /* Simply loop and every 20s update the available allowed ap data */ while (!allowed_ap_worker_exit) @@ -235,6 +252,8 @@ gpointer nm_policy_allowed_ap_refresh_worker (gpointer user_data) } g_thread_exit (0); + + return (NULL); } diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 555363838d..dc7ceea48b 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -140,7 +140,7 @@ gboolean nm_ethernet_address_is_valid (struct ether_addr *test_addr) struct ether_addr invalid_addr2 = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; struct ether_addr invalid_addr3 = { {0x44, 0x44, 0x44, 0x44, 0x44, 0x44} }; - g_return_if_fail (test_addr != NULL); + g_return_val_if_fail (test_addr != NULL, FALSE); /* Compare the AP address the card has with invalid ethernet MAC addresses. */ if ( (memcmp(test_addr, &invalid_addr1, sizeof(struct ether_addr)) != 0) diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 360f1f3f84..946af2ff2e 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -30,11 +30,11 @@ #include "NetworkManager.h" #include "NetworkManagerDevice.h" -#define NM_DEBUG_PRINT( s ) if (debug) fprintf( stderr, s ); -#define NM_DEBUG_PRINT_1( s, a ) if (debug) fprintf( stderr, s, a ); -#define NM_DEBUG_PRINT_2( s, a, b ) if (debug) fprintf( stderr, s, a, b ); -#define NM_DEBUG_PRINT_3( s, a, b, c ) if (debug) fprintf( stderr, s, a, b, c ); -#define NM_DEBUG_PRINT_4( s, a, b, c, d ) if (debug) fprintf( stderr, s, a, b, c, d ); +#define NM_DEBUG_PRINT(s) { if (debug) fprintf(stderr, s); } +#define NM_DEBUG_PRINT_1(s, a) { if (debug) fprintf(stderr, s, a); } +#define NM_DEBUG_PRINT_2(s, a, b) { if (debug) fprintf(stderr, s, a, b); } +#define NM_DEBUG_PRINT_3(s, a, b, c) { if (debug) fprintf(stderr, s, a, b, c); } +#define NM_DEBUG_PRINT_4(s, a, b, c, d) { if (debug) fprintf(stderr, s, a, b, c, d); } gboolean nm_try_acquire_mutex (GMutex *mutex, const char *func); diff --git a/src/NetworkManagerWireless.c b/src/NetworkManagerWireless.c index a4bfce8c7e..cf9ceab92b 100644 --- a/src/NetworkManagerWireless.c +++ b/src/NetworkManagerWireless.c @@ -62,6 +62,7 @@ gboolean nm_wireless_is_most_prefered_ap (NMAccessPoint *ap, int *highest_priori && (nm_null_safe_strcmp (nm_ap_get_essid (allowed_ap), nm_ap_get_essid (ap)) == 0) && (nm_ap_get_priority (allowed_ap) < *highest_priority)) { + *highest_priority = nm_ap_get_priority (allowed_ap); is_most_preferred = TRUE; break; }