2004-07-15 Dan Williams <dcbw@redhat.com>

* 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.


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@15 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams 2004-07-15 16:51:48 +00:00
parent d3ad52d649
commit 088b0d8eb2
15 changed files with 627 additions and 306 deletions

View file

@ -1,3 +1,61 @@
2004-07-15 Dan Williams <dcbw@redhat.com>
* 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 <dcbw@redhat.com>
* dispatcher-daemon/Makefile.am

View file

@ -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

View file

@ -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)\"

View file

@ -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)
{

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -22,6 +22,7 @@
#include <glib.h>
#include <dbus/dbus-glib.h>
#include <stdarg.h>
#include <iwlib.h>
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);

View file

@ -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

View file

@ -24,23 +24,28 @@
#include <dbus/dbus-glib.h>
#include <hal/libhal.h>
#include <iwlib.h>
#include <signal.h>
#include <string.h>
#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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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)

View file

@ -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);

View file

@ -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;
}