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

* dispatcher-daemon/NetworkManagerDispatcher.c
		- A bit more descriptive state message
		- Don't segfault when reading directory

	* src/NetworkManager.h
		- Remove NMData desired_ap member, its now
			per-device rather than global

	* src/NetworkManager.c
		- Remove references to desired_ap
		- Move the allowed AP list refresh stuff into a thread

	* src/NetworkManagerDevice.c
	  src/NetworkManagerDevice.h
		- Each wireless device now has a "best ap"
		- Make device activate/deactivate functions per-device
		- Make wireless scanning per-device
		- Add IPv4 address discover functions, stub IPv6 ones
		- Move ethernet address validation functions to NetworkManagerUtils.c
		- Add wireless access point accessor function
		- Get/Set functions for "best ap"

	* src/NetworkManagerPolicy.c
		- Move activate/deactivate stuff into NetworkManagerDevice.c, per-device
		- Deal with per-device "best ap" rather than data->desired_apa
		- Implement allowed access point worker thread
		- Add nm_policy_essid_is_allowed() function

	* src/NetworkManagerUtils.c
	  src/NetworkManagerUtils.h
	  	- Add nm_ethernet_address_is_valid() function
		- Add IPv4/IPv6 address get functions

	* src/NetworkManagerWireless.c
	  src/NetworkManagerWireless.h
		- Move scanning stuff into NetworkManagerDevice.c, per-device


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@12 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams 2004-07-06 01:34:10 +00:00
parent d340cafffa
commit 019e2337bf
12 changed files with 718 additions and 287 deletions

View file

@ -1,3 +1,42 @@
2004-07-05 Dan Williams <dcbw@redhat.com>
* dispatcher-daemon/NetworkManagerDispatcher.c
- A bit more descriptive state message
- Don't segfault when reading directory
* src/NetworkManager.h
- Remove NMData desired_ap member, its now
per-device rather than global
* src/NetworkManager.c
- Remove references to desired_ap
- Move the allowed AP list refresh stuff into a thread
* src/NetworkManagerDevice.c
src/NetworkManagerDevice.h
- Each wireless device now has a "best ap"
- Make device activate/deactivate functions per-device
- Make wireless scanning per-device
- Add IPv4 address discover functions, stub IPv6 ones
- Move ethernet address validation functions to NetworkManagerUtils.c
- Add wireless access point accessor function
- Get/Set functions for "best ap"
* src/NetworkManagerPolicy.c
- Move activate/deactivate stuff into NetworkManagerDevice.c, per-device
- Deal with per-device "best ap" rather than data->desired_apa
- Implement allowed access point worker thread
- Add nm_policy_essid_is_allowed() function
* src/NetworkManagerUtils.c
src/NetworkManagerUtils.h
- Add nm_ethernet_address_is_valid() function
- Add IPv4/IPv6 address get functions
* src/NetworkManagerWireless.c
src/NetworkManagerWireless.h
- Move scanning stuff into NetworkManagerDevice.c, per-device
2004-06-29 Dan Williams <dcbw@redhat.com>
* dispatcher-daemon/NetworkManagerDispatcher.c

View file

@ -58,7 +58,7 @@ void nmd_execute_scripts (NMDAction action, char *iface_name)
return;
}
while (dir)
do
{
errno = 0;
if ((ent = readdir (dir)) != NULL)
@ -83,9 +83,8 @@ void nmd_execute_scripts (NMDAction action, char *iface_name)
system (cmd);
}
}
else fprintf( stderr, "d_name = %s, errno = %d\n", ent->d_name, errno);
}
}
} while (ent);
closedir (dir);
}
@ -173,7 +172,9 @@ static DBusHandlerResult nmd_dbus_filter (DBusConnection *connection, DBusMessag
{
char *dev_iface_name = nmd_get_device_name (connection, dev_object_path);
fprintf (stderr, "Device %s (%s) now has state %d.\n", dev_object_path, dev_iface_name, action);
fprintf (stderr, "Device %s (%s) is now %s.\n", dev_object_path, dev_iface_name,
(action == NMD_DEVICE_NOW_INACTIVE ? "down" :
(action == NMD_DEVICE_NOW_ACTIVE ? "up" : "error")));
nmd_execute_scripts (action, dev_iface_name);

View file

@ -44,7 +44,7 @@ static GMainLoop *loop = NULL;
static NMData *nm_data = NULL;
gboolean debug = TRUE;
static gboolean quit = FALSE;
extern gboolean allowed_ap_worker_exit;
static void nm_data_free (NMData *data);
@ -342,6 +342,11 @@ gboolean nm_link_state_monitor (gpointer user_data)
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)
*/
/* Implement me */
}
element = g_slist_next (element);
@ -482,7 +487,6 @@ static void nm_data_free (NMData *data)
nm_device_unref (data->active_device);
nm_data_allowed_ap_list_free (data);
nm_ap_unref (data->desired_ap);
}
@ -546,6 +550,7 @@ int main( int argc, char *argv[] )
guint policy_source;
guint wireless_scan_source;
gboolean become_daemon = TRUE;
GThread *allowed_ap_thread = NULL;
/* Parse options */
while (1)
@ -649,6 +654,7 @@ int main( int argc, char *argv[] )
/* Initialize our list of allowed access points */
nm_policy_update_allowed_access_points (nm_data);
allowed_ap_thread = g_thread_create (nm_policy_allowed_ap_refresh_worker, nm_data, FALSE, NULL);
/* Create our dbus service */
nm_data->dbus_connection = nm_dbus_init ();
@ -670,19 +676,19 @@ int main( int argc, char *argv[] )
wireless_scan_source = g_timeout_add (10000, nm_wireless_scan_monitor, nm_data);
/* Watch all devices that HAL knows about for state changes */
/* Don't need this now because our polling function takes care of it and
* HAL drops the ball for some cards.
*/
hal_device_property_watch_all (nm_data->hal_ctx);
/* Since we do what dhclient does, and do it better, kill dhclient */
/* We run dhclient when we need to, and we don't want any stray ones
* lying around upon launch.
*/
system ("killall dhclient");
/* Run the main loop, all events processed by callbacks from libhal. */
/* Wheeee!!! */
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
/* Kill the watch functions */
/* Kill the watch functions & threads */
allowed_ap_worker_exit = TRUE;
g_source_remove (link_source);
g_source_remove (policy_source);
g_source_remove (wireless_scan_source);

View file

@ -37,7 +37,6 @@ struct NMData
GMutex *state_modified_mutex;
GSList *allowed_ap_list;
GMutex *allowed_ap_list_mutex;
NMAccessPoint *desired_ap;
DBusConnection *dbus_connection;
};

View file

@ -24,8 +24,6 @@
#include <dbus/dbus-glib.h>
#include <hal/libhal.h>
#include <iwlib.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include "NetworkManager.h"
#include "NetworkManagerDevice.h"
@ -165,6 +163,7 @@ typedef struct NMDeviceWirelessOptions
gboolean supports_wireless_scan;
GMutex *ap_list_mutex;
GSList *ap_list;
NMAccessPoint *best_ap;
} NMDeviceWirelessOptions;
typedef struct NMDeviceWiredOptions
@ -188,6 +187,8 @@ struct NMDevice
gchar *iface;
NMIfaceType iface_type;
gboolean link_active;
guint32 ip_address;
/* FIXME: ipv6 address too */
NMDeviceOptions dev_options;
};
@ -263,6 +264,7 @@ void nm_device_unref (NMDevice *dev)
{
g_free (dev->dev_options.wireless.cur_essid);
g_mutex_free (dev->dev_options.wireless.ap_list_mutex);
nm_ap_unref (dev->dev_options.wireless.best_ap);
}
dev->udi = NULL;
@ -350,11 +352,11 @@ gboolean nm_device_get_supports_wireless_scan (NMDevice *dev)
* Updates the link state for a particular device.
*
*/
gboolean nm_device_update_link_active (NMDevice *dev, gboolean check_mii)
void nm_device_update_link_active (NMDevice *dev, gboolean check_mii)
{
gboolean link_active = FALSE;
g_return_val_if_fail (dev != NULL, FALSE);
g_return_if_fail (dev != NULL);
/* FIXME
* For wireless cards, the best indicator of a "link" at this time
@ -371,23 +373,7 @@ gboolean nm_device_update_link_active (NMDevice *dev, gboolean check_mii)
iwlib_socket = iw_sockets_open ();
if (iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0)
{
struct ether_addr invalid_addr1;
struct ether_addr invalid_addr2;
struct ether_addr invalid_addr3;
struct ether_addr ap_addr;
/* Compare the AP address the card has with invalid ethernet MAC addresses.
*/
memcpy (&ap_addr, &(wrq.u.ap_addr.sa_data), sizeof (struct ether_addr));
memset (&invalid_addr1, 0xFF, sizeof(struct ether_addr));
memset (&invalid_addr2, 0x00, sizeof(struct ether_addr));
memset (&invalid_addr2, 0x44, sizeof(struct ether_addr));
if ( (memcmp(&ap_addr, &invalid_addr1, sizeof(struct ether_addr)) != 0)
&& (memcmp(&ap_addr, &invalid_addr2, sizeof(struct ether_addr)) != 0)
&& (memcmp(&ap_addr, &invalid_addr3, sizeof(struct ether_addr)) != 0))
link_active = TRUE;
}
link_active = nm_ethernet_address_is_valid (&(wrq.u.ap_addr.sa_data));
close (iwlib_socket);
break;
}
@ -413,7 +399,6 @@ gboolean nm_device_update_link_active (NMDevice *dev, gboolean check_mii)
nm_device_set_link_active (dev, link_active);
nm_data_set_state_modified (nm_get_global_data(), TRUE);
}
return (link_active);
}
@ -499,6 +484,30 @@ void nm_device_set_essid (NMDevice *dev, const char *essid)
}
/*
* nm_device_get_ap_address
*
* If a device is wireless, get the access point's ethernet address
* that the card is associated with.
*/
void nm_device_get_ap_address (NMDevice *dev, struct ether_addr *addr)
{
int iwlib_socket;
struct iwreq wrq;
g_return_if_fail (dev != NULL);
g_return_if_fail (addr != NULL);
/* Do we have a valid MAC address? */
iwlib_socket = iw_sockets_open ();
if (iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0)
memcpy (addr, &(wrq.u.ap_addr.sa_data), sizeof (struct ether_addr));
else
memset (addr, 0, sizeof (struct ether_addr));
close (iwlib_socket);
}
/*
* nm_device_set_wep_key
*
@ -564,6 +573,46 @@ void nm_device_set_wep_key (NMDevice *dev, const char *wep_key)
}
/*
* nm_device_get_ip4_address
*
* Get a device's IPv4 address
*
*/
guint32 nm_device_get_ip4_address(NMDevice *dev)
{
struct ifreq req;
int socket;
g_return_val_if_fail (dev != NULL, 0);
g_return_val_if_fail (nm_device_get_iface (dev) != NULL, 0);
socket = nm_get_network_control_socket ();
if (socket < 0)
return (0);
strncpy ((char *)(&req.ifr_name), nm_device_get_iface (dev), 16); // 16 == IF_NAMESIZE
if (ioctl (socket, SIOCGIFADDR, &req) != 0)
return (0);
return (((struct sockaddr_in *)(&req.ifr_addr))->sin_addr.s_addr);
}
/*
* nm_device_get_ip6_address
*
* Get a device's IPv6 address
*
*/
void nm_device_get_ip6_address(NMDevice *dev)
{
/* FIXME
* Implement
*/
}
/*
* nm_device_set_up_down
*
@ -651,6 +700,158 @@ gboolean nm_device_is_up (NMDevice *dev)
}
/*
* nm_device_activate
*
* Activate the device, bringing it up and getting it an
* IP address.
*
*/
gboolean nm_device_activate (NMDevice *dev)
{
unsigned char buf[500];
gboolean success = FALSE;
unsigned char *iface;
unsigned char hostname[500] = "\0";
int host_err;
NMData *data = nm_get_global_data ();
int dhclient_err;
FILE *pidfile;
g_return_val_if_fail (dev != NULL, FALSE);
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)
{
NMAccessPoint *ap = nm_device_get_best_ap (dev);
/* If the card is just inserted, we may not have had a chance to scan yet */
if (!ap)
{
nm_device_do_wireless_scan (dev);
ap = nm_device_get_best_ap (dev);
}
/* If there is a desired AP to connect to, use that essid and possible WEP key */
if (nm_ap_get_essid (ap) != NULL)
{
nm_device_bring_down (dev);
nm_device_set_essid (dev, nm_ap_get_essid (ap));
/* Disable WEP */
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));
}
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 */
if (!nm_device_is_up (dev));
nm_device_bring_up (dev);
/* Kill the old default route */
snprintf (buf, 500, "/sbin/ip route del default");
system (buf);
/* Find and kill the previous dhclient process for this interface */
iface = nm_device_get_iface (dev);
snprintf (buf, 500, "/var/run/dhclient-%s.pid", iface);
pidfile = fopen (buf, "r");
if (pidfile)
{
int len;
unsigned char s_pid[20];
pid_t n_pid = -1;
memset (s_pid, 0, 20);
fgets (s_pid, 19, pidfile);
len = strnlen (s_pid, 20);
fclose (pidfile);
n_pid = atoi (s_pid);
if (n_pid > 0)
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)
{
/* 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_get_iface_type (dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET)
{
nm_device_set_essid (dev, "");
nm_device_set_wep_key (dev, NULL);
}
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);
nm_dbus_signal_device_now_active (data->dbus_connection, dev);
return (success);
}
/*
* nm_device_deactivate
*
* Remove a device's routing table entries and IP address.
*
*/
gboolean nm_device_deactivate (NMDevice *dev)
{
unsigned char buf[500];
unsigned char *iface;
gboolean success = FALSE;
NMData *data = nm_get_global_data ();
g_return_val_if_fail (dev != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
iface = nm_device_get_iface (dev);
/* Take out any entries in the routing table and any IP address the old interface
* had.
*/
if (iface && strlen (iface))
{
/* Remove routing table entries */
snprintf (buf, 500, "/sbin/ip route flush dev %s", iface);
system (buf);
/* Remove ip address */
snprintf (buf, 500, "/sbin/ip address flush dev %s", iface);
system (buf);
success = TRUE;
}
nm_dbus_signal_device_no_longer_active (data->dbus_connection, dev);
return (success);
}
/*
* nm_device_ap_list_add
*
@ -712,7 +913,7 @@ void nm_device_ap_list_clear (NMDevice *dev)
/*
* nm_device_ap_list_get_copy
* nm_device_ap_list_get_ap
*
* Copy the list of ESSIDs
*
@ -751,6 +952,255 @@ NMAccessPoint *nm_device_ap_list_get_ap (NMDevice *dev, int index)
}
/*
* Get/Set functions for "best" access point
*
*/
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);
return (dev->dev_options.wireless.best_ap);
}
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);
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;
}
/*
* nm_device_do_normal_scan
*
* Scan for access points on cards that support wireless scanning.
*
*/
static void nm_device_do_normal_scan (NMDevice *dev)
{
int iwlib_socket;
g_return_if_fail (dev != NULL);
/* Device must be up before we can scan */
if (!nm_device_is_up (dev))
nm_device_bring_up (dev);
iwlib_socket = iw_sockets_open ();
if (iwlib_socket >= 0)
{
wireless_scan_head scan_results = { NULL, 0 };
wireless_scan *tmp_ap;
int err;
NMAccessPoint *highest_priority_ap = NULL;
int highest_priority = NM_AP_PRIORITY_WORST;
/* Clear out the device's ap list */
nm_device_ap_list_clear (dev);
err = iw_scan (iwlib_socket, nm_device_get_iface (dev), WIRELESS_EXT, &scan_results);
/* Iterate over scan results and pick a "most" preferred access point. */
tmp_ap = scan_results.result;
while (tmp_ap)
{
/* Blank essids usually indicate an AP that is not broadcasting its essid,
* but since its not broadcasting the essid, we cannot use that ap yet.
*/
if (tmp_ap->b.has_essid && tmp_ap->b.essid_on && (strlen (tmp_ap->b.essid) > 0))
{
NMAccessPoint *nm_ap = nm_ap_new ();
/* 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];
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);
}
nm_ap_set_quality (nm_ap, tmp_ap->stats.qual.qual);
if (tmp_ap->b.has_freq)
nm_ap_set_freq (nm_ap, tmp_ap->b.freq);
/* Add the AP to the device's AP list, no matter if its allowed or not */
nm_device_ap_list_add (dev, nm_ap);
if (nm_wireless_is_most_prefered_ap (nm_ap, &highest_priority))
{
if (highest_priority_ap)
nm_ap_unref (highest_priority_ap);
highest_priority_ap = nm_ap_new_from_ap (nm_ap);
}
nm_ap_unref (nm_ap);
}
tmp_ap = tmp_ap->next;
}
nm_dispose_scan_results (scan_results.result);
/* If we have the "most" preferred access point, and its different than the current
* access point, switch to it during the next cycle.
*/
if ( highest_priority_ap
&& (!nm_device_get_best_ap (dev) || (nm_null_safe_strcmp (nm_device_get_essid (dev), nm_ap_get_essid (highest_priority_ap)) != 0)))
{
nm_device_set_best_ap (dev, nm_ap_new_from_ap (highest_priority_ap));
nm_data_set_state_modified (nm_get_global_data (), TRUE);
nm_ap_unref (highest_priority_ap);
}
close (iwlib_socket);
}
else
NM_DEBUG_PRINT_1 ("nm_device_do_normal_scan() could not get a control socket for the wireless card %s.\n", nm_device_get_iface (dev) );
}
/*
* nm_device_do_pseudo_scan
*
* Brute-force the allowed access point list to find one that works, if any.
*
* FIXME
* There's probably a better way to do the non-scanning access point discovery
* than brute forcing it like this, but that makes the state machine here oh so
* much more complicated.
*/
static void nm_device_do_pseudo_scan (NMDevice *dev)
{
NMData *data = nm_get_global_data ();
g_return_if_fail (data != NULL);
g_return_if_fail (dev != NULL);
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__))
{
GSList *element = data->allowed_ap_list;
/* Turn off the essid so we can tell if its changed when
* we set it below.
*/
nm_device_set_essid (dev, "");
while (element)
{
NMAccessPoint *ap = (NMAccessPoint *)(element->data);
/* 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);
/* Save the MAC address */
nm_device_get_ap_address (dev, &save_ap_addr);
nm_device_set_essid (dev, nm_ap_get_essid (ap));
if (nm_ap_get_wep_key (ap))
nm_device_set_wep_key (dev, nm_ap_get_wep_key (ap));
else
nm_device_set_wep_key (dev, NULL);
/* Wait a bit for association */
g_usleep (G_USEC_PER_SEC * 2);
/* 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)
* will let the essid change, but the the card won't actually de-associate
* from the previous access point if it can't associate with the new one
* (ie signal too weak, etc).
*/
if (valid && (memcmp (&save_ap_addr, &cur_ap_addr, sizeof (struct ether_addr)) == 0))
valid = FALSE;
/* FIXME
* We should probably lock access to data->desired_ap
*/
if (valid)
{
fprintf( stderr, "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;
}
}
element = g_slist_next (element);
}
nm_unlock_mutex (data->allowed_ap_list_mutex, __FUNCTION__);
fprintf( stderr, "Try all done.\n");
}
nm_device_unref (dev);
}
/*
* nm_device_do_wireless_scan
*
* Get a list of access points this device can see.
*
*/
void nm_device_do_wireless_scan (NMDevice *dev)
{
NMData *data = nm_get_global_data ();
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);
if (nm_device_get_supports_wireless_scan (dev))
nm_device_do_normal_scan (dev);
else
{
struct ether_addr ap_addr;
/* We can't pseudo-scan without switching APs, therefore
* if the card has a valid access point and its an allowed
* access point, don't pseudo-scan for others.
*/
nm_device_get_ap_address (dev, &ap_addr);
if ( !nm_ethernet_address_is_valid (&ap_addr)
|| !nm_policy_essid_is_allowed (data, nm_device_get_essid (dev))
|| !nm_device_get_best_ap (dev))
{
nm_device_do_pseudo_scan (dev);
}
}
}
/****************************************/
/* Code ripped from HAL */
/* minor modifications made for */

View file

@ -23,6 +23,7 @@
#define NETWORK_MANAGER_DEVICE_H
#include "NetworkManager.h"
#include <net/ethernet.h>
/*
* Types of NetworkManager devices
@ -53,18 +54,29 @@ NMIfaceType nm_device_get_iface_type (NMDevice *dev);
gboolean nm_device_get_link_active (NMDevice *dev);
void nm_device_set_link_active (NMDevice *dev, const gboolean active);
gboolean nm_device_update_link_active (NMDevice *dev, gboolean check_mii);
gboolean nm_device_check_link_status (NMDevice *dev);
void nm_device_update_link_active (NMDevice *dev, gboolean check_mii);
char * nm_device_get_essid (NMDevice *dev);
void nm_device_set_essid (NMDevice *dev, const char *essid);
void nm_device_get_ap_address (NMDevice *dev, struct ether_addr *addr);
guint32 nm_device_get_ip4_address (NMDevice *dev);
void nm_device_update_ip4_address (NMDevice *dev);
void nm_device_get_ip6_address (NMDevice *dev);
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);
/* 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);
void nm_device_bring_up (NMDevice *dev);
void nm_device_bring_down (NMDevice *dev);
gboolean nm_device_is_up (NMDevice *dev);

View file

@ -1,3 +1,4 @@
/* NetworkManager -- Network link manager
*
* Dan Williams <dcbw@redhat.com>
@ -26,137 +27,16 @@
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/select.h>
#include "NetworkManagerPolicy.h"
#include "NetworkManagerUtils.h"
#include "NetworkManagerAP.h"
gboolean allowed_ap_worker_exit = FALSE;
extern gboolean debug;
/*
* nm_policy_activate_device
*
* Performs interface switching and related networking goo.
*
*/
static void nm_policy_switch_device (NMData *data, NMDevice *switch_to_dev, NMDevice *old_dev)
{
unsigned char buf[500];
unsigned char hostname[500] = "\0";
const unsigned char *new_iface;
int host_err;
int dhclient_err;
FILE *pidfile;
g_return_if_fail (data != NULL);
g_return_if_fail (switch_to_dev != NULL);
g_return_if_fail (nm_device_get_iface (switch_to_dev));
g_return_if_fail (strlen (nm_device_get_iface (switch_to_dev)) >= 0);
/* If its a wireless device, set the ESSID and WEP key */
if (nm_device_get_iface_type (switch_to_dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET)
{
/* If there is a desired AP to connect to, use that essid and possible WEP key */
if ( data->desired_ap
&& (nm_ap_get_essid (data->desired_ap) != NULL))
{
nm_device_bring_down (switch_to_dev);
nm_device_set_essid (switch_to_dev, nm_ap_get_essid (data->desired_ap));
/* Disable WEP */
nm_device_set_wep_key (switch_to_dev, NULL);
if (nm_ap_get_wep_key (data->desired_ap))
nm_device_set_wep_key (switch_to_dev, nm_ap_get_wep_key (data->desired_ap));
}
else
{
/* If the card isn't up, bring it up so that we can scan. We may be too early here to have
* gotten all the scanning results, and therefore have no desired_ap. Just wait.
*/
if (!nm_device_is_up (switch_to_dev));
nm_device_bring_up (switch_to_dev);
NM_DEBUG_PRINT ("nm_policy_activate_interface() could not find a desired AP. Card doesn't support scanning?\n");
return; /* Don't associate with any non-allowed access points */
}
NM_DEBUG_PRINT_1 ("nm_policy_activate_interface() using essid '%s'\n", nm_ap_get_essid (data->desired_ap));
}
host_err = gethostname (hostname, 500);
/* Take out any entries in the routing table and any IP address the old interface
* had.
*/
if (old_dev && strlen (nm_device_get_iface (old_dev)))
{
/* Remove routing table entries */
snprintf (buf, 500, "/sbin/ip route flush dev %s", nm_device_get_iface (old_dev));
system (buf);
/* Remove ip address */
snprintf (buf, 500, "/sbin/ip address flush dev %s", nm_device_get_iface (old_dev));
system (buf);
}
/* Bring the device up */
if (!nm_device_is_up (switch_to_dev));
nm_device_bring_up (switch_to_dev);
/* Kill the old default route */
snprintf (buf, 500, "/sbin/ip route del default");
system (buf);
/* Find and kill the previous dhclient process for this interface */
new_iface = nm_device_get_iface (switch_to_dev);
snprintf (buf, 500, "/var/run/dhclient-%s.pid", new_iface);
pidfile = fopen (buf, "r");
if (pidfile)
{
int len;
unsigned char s_pid[20];
pid_t n_pid = -1;
memset (s_pid, 0, 20);
fgets (s_pid, 19, pidfile);
len = strnlen (s_pid, 20);
fclose (pidfile);
n_pid = atoi (s_pid);
if (n_pid > 0)
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",
new_iface, new_iface, new_iface, new_iface);
dhclient_err = system (buf);
if (dhclient_err != 0)
{
/* Wireless devices cannot be down if they are the active interface,
* otherwise we cannot use them for scanning.
*/
if (nm_device_get_iface_type (switch_to_dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET)
{
nm_device_set_essid (switch_to_dev, "");
nm_device_set_wep_key (switch_to_dev, NULL);
nm_device_bring_up (switch_to_dev);
}
}
/* Set the hostname back to what it was before so that X11 doesn't
* puke when the hostname changes, so that 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_state_modification_monitor
*
@ -276,13 +156,11 @@ gboolean nm_state_modification_monitor (gpointer user_data)
*/
if (nm_device_get_iface_type (highest_priority_dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET)
{
/* If we don't yet have a desired AP, attempt to get one. */
if (!data->desired_ap)
nm_wireless_do_scan (data, highest_priority_dev);
NMAccessPoint *ap = nm_device_get_best_ap (highest_priority_dev);
if ( data->desired_ap
&& (nm_null_safe_strcmp (nm_device_get_essid (highest_priority_dev), nm_ap_get_essid (data->desired_ap)) != 0)
&& (strlen (nm_ap_get_essid (data->desired_ap)) > 0))
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;
}
@ -302,9 +180,7 @@ gboolean nm_state_modification_monitor (gpointer user_data)
* after a main loop iteration, we make a much more complicated state machine.
*/
if (data->active_device)
nm_dbus_signal_device_no_longer_active (data->dbus_connection, data->active_device);
nm_policy_switch_device (data, highest_priority_dev, data->active_device);
nm_device_deactivate (data->active_device);
if (data->active_device)
nm_device_unref (data->active_device);
@ -312,7 +188,7 @@ gboolean nm_state_modification_monitor (gpointer user_data)
data->active_device = highest_priority_dev;
nm_device_ref (data->active_device);
nm_dbus_signal_device_now_active (data->dbus_connection, data->active_device);
nm_device_activate (data->active_device);
NM_DEBUG_PRINT ("**** Switched.\n");
}
@ -327,6 +203,41 @@ gboolean nm_state_modification_monitor (gpointer user_data)
}
/*
* nm_policy_allowed_ap_refresh_worker
*
* Worker thread function to periodically refresh the allowed
* access point list with updated data.
*
*/
gpointer nm_policy_allowed_ap_refresh_worker (gpointer user_data)
{
NMData *data = (NMData *)(user_data);
struct timeval timeout;
g_return_if_fail (data != NULL);
/* Simply loop and every 20s update the available allowed ap data */
while (!allowed_ap_worker_exit)
{
int err;
timeout.tv_sec = 20;
timeout.tv_usec = 0;
/* Wait, but don't execute the update if select () returned an error,
* since it may have immediately returned, so that we don't hammer
* GConf (or the hard drive).
*/
err = select (0, NULL, NULL, NULL, &timeout);
if (err >= 0)
nm_policy_update_allowed_access_points (data);
}
g_thread_exit (0);
}
/*
* nm_policy_update_allowed_access_points
*
@ -341,7 +252,7 @@ void nm_policy_update_allowed_access_points (NMData *data)
g_return_if_fail (data != NULL);
if (nm_try_acquire_mutex (data->allowed_ap_list_mutex, NULL))
if (nm_try_acquire_mutex (data->allowed_ap_list_mutex, __FUNCTION__))
{
ap_file = fopen (NM_ALLOWED_AP_FILE, "r");
if (ap_file)
@ -425,11 +336,49 @@ void nm_policy_update_allowed_access_points (NMData *data)
fclose (ap_file);
}
else
NM_DEBUG_PRINT_1( "nm_policy_update_allowed_access_points() could not open and lock allowed ap list file %s. errno %d\n", NM_ALLOWED_AP_FILE );
NM_DEBUG_PRINT_2( "nm_policy_update_allowed_access_points() could not open allowed ap list file %s. errno %d\n", NM_ALLOWED_AP_FILE, errno );
nm_unlock_mutex (data->allowed_ap_list_mutex, NULL);
nm_unlock_mutex (data->allowed_ap_list_mutex, __FUNCTION__);
}
else
NM_DEBUG_PRINT( "nm_policy_update_allowed_access_points() could not lock allowed ap list mutex\n" );
}
/*
* nm_policy_essid_is_allowed
*
* Searches for a specific essid in the list of allowed access points.
*/
gboolean nm_policy_essid_is_allowed (NMData *data, const unsigned char *essid)
{
gboolean allowed = FALSE;
g_return_val_if_fail (data != NULL, FALSE);
g_return_val_if_fail (essid != NULL, FALSE);
if (strlen (essid) <= 0)
return FALSE;
/* Acquire allowed AP list mutex, silently fail if we cannot */
if (nm_try_acquire_mutex (data->allowed_ap_list_mutex, __FUNCTION__))
{
GSList *element = data->allowed_ap_list;
while (element)
{
NMAccessPoint *ap = (NMAccessPoint *)(element->data);
if (ap && (nm_null_safe_strcmp (nm_ap_get_essid (ap), essid) == 0))
{
allowed = TRUE;
break;
}
element = g_slist_next (element);
}
nm_unlock_mutex (data->allowed_ap_list_mutex, __FUNCTION__);
}
return (allowed);
}

View file

@ -25,8 +25,12 @@
#include "NetworkManager.h"
#include "NetworkManagerDevice.h"
gboolean nm_state_modification_monitor (gpointer user_data);
gboolean nm_state_modification_monitor (gpointer user_data);
void nm_policy_update_allowed_access_points (NMData *data);
void nm_policy_update_allowed_access_points (NMData *data);
gboolean nm_policy_essid_is_allowed (NMData *data, const unsigned char *essid);
gpointer nm_policy_allowed_ap_refresh_worker (gpointer user_data);
#endif

View file

@ -23,6 +23,7 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include "NetworkManager.h"
#include "NetworkManagerUtils.h"
@ -126,6 +127,30 @@ int nm_get_network_control_socket (void)
}
/*
* nm_ethernet_address_is_valid
*
* Compares an ethernet address against known invalid addresses.
*
*/
gboolean nm_ethernet_address_is_valid (struct ether_addr *test_addr)
{
gboolean valid = FALSE;
struct ether_addr invalid_addr1 = { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} };
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);
/* Compare the AP address the card has with invalid ethernet MAC addresses. */
if ( (memcmp(test_addr, &invalid_addr1, sizeof(struct ether_addr)) != 0)
&& (memcmp(test_addr, &invalid_addr2, sizeof(struct ether_addr)) != 0)
&& (memcmp(test_addr, &invalid_addr3, sizeof(struct ether_addr)) != 0))
valid = TRUE;
return (valid);
}
/*
* nm_dispose_scan_results
@ -145,3 +170,43 @@ void nm_dispose_scan_results (wireless_scan *result_list)
free (tmp2);
}
}
/*
* nm_get_ip4_address_for_device
*
* Get a device's IPv4 address
*
*/
guint32 nm_get_ip4_address_for_device(NMDevice *dev)
{
struct ifreq req;
int socket;
g_return_val_if_fail (dev != NULL, 0);
g_return_val_if_fail (nm_device_get_iface (dev) != NULL, 0);
socket = nm_get_network_control_socket ();
if (socket < 0)
return (0);
strncpy ((char *)(&req.ifr_name), nm_device_get_iface (dev), 16); // 16 == IF_NAMESIZE
if (ioctl (socket, SIOCGIFADDR, &req) != 0)
return (0);
return (((struct sockaddr_in *)(&req.ifr_addr))->sin_addr.s_addr);
}
/*
* nm_get_ip6_address_for_device
*
* Get a device's IPv6 address
*
*/
void nm_get_ip6_address_for_device(NMDevice *dev)
{
/* FIXME
* Implement
*/
}

View file

@ -24,9 +24,11 @@
#include <glib.h>
#include <stdio.h>
#include <net/ethernet.h>
#include <iwlib.h>
#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 );
@ -42,6 +44,11 @@ int nm_null_safe_strcmp (const char *s1, const char *s2);
int nm_get_network_control_socket (void);
gboolean nm_ethernet_address_is_valid (struct ether_addr *test_addr);
void nm_dispose_scan_results (wireless_scan *result_list);
guint32 nm_get_ipv4_address_for_device (NMDevice *dev);
void nm_get_ipv6_address_for_device (NMDevice *dev);
#endif

View file

@ -37,7 +37,7 @@ extern gboolean debug;
* both allowed _and_ has a better priority than highest_priority.
*
*/
static gboolean nm_wireless_is_most_prefered_ap (NMAccessPoint *ap, int *highest_priority)
gboolean nm_wireless_is_most_prefered_ap (NMAccessPoint *ap, int *highest_priority)
{
NMData *data = nm_get_global_data ();
GSList *element;
@ -77,108 +77,6 @@ static gboolean nm_wireless_is_most_prefered_ap (NMAccessPoint *ap, int *highest
}
/*
* nm_wireless_do_scan
*
* Runs the actual scan fore access points.
*
*/
void nm_wireless_do_scan (NMData *data, NMDevice *dev)
{
int iwlib_socket;
g_return_if_fail (data != NULL);
g_return_if_fail (dev != NULL);
if (nm_device_get_iface_type (dev) != NM_IFACE_TYPE_WIRELESS_ETHERNET)
return;
if (nm_device_get_supports_wireless_scan (dev) == FALSE)
return;
/* Device must be up before we can scan */
if (!nm_device_is_up (dev))
nm_device_bring_up (dev);
iwlib_socket = iw_sockets_open ();
if (iwlib_socket >= 0)
{
wireless_scan_head scan_results = { NULL, 0 };
wireless_scan *tmp_ap;
int err;
NMAccessPoint *highest_priority_ap = NULL;
int highest_priority = NM_AP_PRIORITY_WORST;
/* Clear out the device's ap list */
nm_device_ap_list_clear (dev);
err = iw_scan (iwlib_socket, nm_device_get_iface (dev), WIRELESS_EXT, &scan_results);
/* Iterate over scan results and pick a "most" preferred access point. */
tmp_ap = scan_results.result;
while (tmp_ap)
{
/* Blank essids usually indicate an AP that is not broadcasting its essid,
* but since its not broadcasting the essid, we cannot use that ap yet.
*/
if (tmp_ap->b.has_essid && tmp_ap->b.essid_on && (strlen (tmp_ap->b.essid) > 0))
{
NMAccessPoint *nm_ap = nm_ap_new ();
/* 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];
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);
}
nm_ap_set_quality (nm_ap, tmp_ap->stats.qual.qual);
if (tmp_ap->b.has_freq)
nm_ap_set_freq (nm_ap, tmp_ap->b.freq);
/* Add the AP to the device's AP list, no matter if its allowed or not */
nm_device_ap_list_add (dev, nm_ap);
if (nm_wireless_is_most_prefered_ap (nm_ap, &highest_priority))
{
if (highest_priority_ap)
nm_ap_unref (highest_priority_ap);
highest_priority_ap = nm_ap_new_from_ap (nm_ap);
}
nm_ap_unref (nm_ap);
}
tmp_ap = tmp_ap->next;
}
nm_dispose_scan_results (scan_results.result);
/* If we have the "most" preferred access point, and its different than the current
* access point, switch to it during the next cycle.
*/
if ( highest_priority_ap
&& (!data->desired_ap || (nm_null_safe_strcmp (nm_device_get_essid (dev), nm_ap_get_essid (highest_priority_ap)) != 0)))
{
if (data->desired_ap)
nm_ap_unref (data->desired_ap);
data->desired_ap = nm_ap_new_from_ap (highest_priority_ap);
data->state_modified = TRUE;
nm_ap_unref (highest_priority_ap);
}
close (iwlib_socket);
}
else
NM_DEBUG_PRINT ("nm_wireless_do_scan() could not get a control socket for the wireless card.\n" );
}
/*
* nm_wireless_scan_monitor
*
@ -188,23 +86,19 @@ void nm_wireless_do_scan (NMData *data, NMDevice *dev)
gboolean nm_wireless_scan_monitor (gpointer user_data)
{
NMData *data = (NMData *)user_data;
GSList *element;
NMDevice *dev;
g_return_val_if_fail (data != NULL, TRUE);
if (!data->active_device)
return (TRUE);
/* Grab a current list of allowed access points */
nm_policy_update_allowed_access_points (data);
/* Attempt to acquire mutex for device list iteration.
/* Attempt to acquire mutex so that data->active_device sticks around.
* If the acquire fails, just ignore the scan completely.
*/
if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__))
{
if (data->active_device && (nm_device_get_iface_type (data->active_device) == NM_IFACE_TYPE_WIRELESS_ETHERNET))
nm_wireless_do_scan (data, data->active_device);
nm_device_do_wireless_scan (data->active_device);
nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__);
}

View file

@ -22,6 +22,11 @@
#ifndef NETWORK_MANAGER_WIRELESS_H
#define NETWORK_MANAGER_WIRELESS_H
#include "NetworkManager.h"
#include "NetworkManagerDevice.h"
gboolean nm_wireless_is_most_prefered_ap (NMAccessPoint *ap, int *highest_priority);
gboolean nm_wireless_scan_monitor (gpointer user_data);