diff --git a/src/NetworkManager.c b/src/NetworkManager.c index b4a921488..4bc06c60b 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -47,75 +47,93 @@ */ static GMainLoop *loop = NULL; static NMData *nm_data = NULL; -gboolean debug = TRUE; extern gboolean allowed_ap_worker_exit; static void nm_data_free (NMData *data); +/* + * nm_get_device_interface_from_hal + * + * Queries HAL for the "net.interface" property of a device and returns + * it if successful. + * + */ +static char *nm_get_device_interface_from_hal (LibHalContext *ctx, const char *udi) +{ + char *iface = NULL; + + if (hal_device_property_exists (ctx, udi, "net.interface")) + { + char *temp = hal_device_get_property_string (ctx, udi, "net.interface"); + iface = g_strdup (temp); + hal_free_string (temp); + } + + return (iface); +} + + /* * nm_create_device_and_add_to_list * - * Create a new NLM device and add it to our device list. + * Create a new network device and add it to our device list. * * Returns: newly allocated device on success * NULL on failure */ -NMDevice * nm_create_device_and_add_to_list (NMData *data, const char *udi) +NMDevice * nm_create_device_and_add_to_list (NMData *data, const char *udi, const char *iface, + gboolean test_device, NMDeviceType test_device_type) { NMDevice *dev = NULL; - gboolean success = FALSE; g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (udi != NULL, NULL); + g_return_val_if_fail (iface != NULL, NULL); - if (hal_device_property_exists (data->hal_ctx, udi, "net.interface")) + /* If we are called to create a test devices, but test devices weren't enabled + * on the command-line, don't create the device. + */ + if (!data->enable_test_devices && test_device) { - gchar *iface_name = hal_device_get_property_string (data->hal_ctx, udi, "net.interface"); + syslog (LOG_ERR, "nm_create_device_and_add_to_list(): attempt to create a test device," + " but test devices were not enabled on the command line. Will not create the device.\n"); + return (NULL); + } - /* Make sure the device is not already in the device list */ - if ((dev = nm_get_device_by_iface (data, iface_name))) + /* Make sure the device is not already in the device list */ + if ((dev = nm_get_device_by_iface (data, iface))) + return (NULL); + + if ((dev = nm_device_new (iface, test_device, test_device_type, data))) + { + /* Build up the device structure */ + nm_device_set_udi (dev, udi); + + /* Attempt to acquire mutex for device list addition. If acquire fails, + * just ignore the device addition entirely. + */ + if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__)) { - hal_free_string (iface_name); - return (NULL); - } + syslog( LOG_INFO, "nm_create_device_and_add_to_list(): adding device '%s' (%s)", + nm_device_get_iface (dev), nm_device_is_wireless (dev) ? "wireless" : "wired" ); - if ((dev = nm_device_new (iface_name, data))) - { + data->dev_list = g_slist_append (data->dev_list, dev); + nm_device_deactivate (dev, TRUE); - /* Build up the device structure */ - nm_device_set_udi (dev, udi); + nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); - /* Attempt to acquire mutex for device list addition. If acquire fails, - * just ignore the device addition entirely. - */ - if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__)) - { - syslog( LOG_INFO, "nm_create_device_and_add_to_list(): adding device '%s' (%s)", - nm_device_get_iface (dev), nm_device_is_wireless (dev) ? "wireless" : "wired" ); - - data->dev_list = g_slist_append (data->dev_list, dev); - nm_device_deactivate (dev, TRUE); - success = TRUE; - - nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); - } else syslog( LOG_ERR, "nm_create_device_and_add_to_list() could not acquire device list mutex." ); - } else syslog( LOG_ERR, "nm_create_device_and_add_to_list() could not allocate device data." ); - - hal_free_string (iface_name); - - if (success) - { - nm_data_set_state_modified (data, TRUE); + nm_data_mark_state_changed (data); nm_dbus_signal_device_status_change (data->dbus_connection, dev, DEVICE_LIST_CHANGE); } else { /* If we couldn't add the device to our list, free its data. */ + syslog( LOG_ERR, "nm_create_device_and_add_to_list() could not acquire device list mutex." ); nm_device_unref (dev); dev = NULL; } - } + } else syslog( LOG_ERR, "nm_create_device_and_add_to_list() could not allocate device data." ); return (dev); } @@ -159,14 +177,14 @@ void nm_remove_device_from_list (NMData *data, const char *udi) data->user_device = NULL; } - nm_device_activation_cancel (dev); + nm_device_activation_signal_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); + nm_data_mark_state_changed (data); nm_dbus_signal_device_status_change (data->dbus_connection, dev, DEVICE_LIST_CHANGE); break; @@ -194,7 +212,8 @@ static void nm_hal_mainloop_integration (LibHalContext *ctx, DBusConnection * db */ static void nm_hal_device_added (LibHalContext *ctx, const char *udi) { - NMData *data = (NMData *)hal_ctx_get_user_data (ctx); + NMData *data = (NMData *)hal_ctx_get_user_data (ctx); + char *iface = NULL; g_return_if_fail (data != NULL); @@ -204,7 +223,11 @@ static void nm_hal_device_added (LibHalContext *ctx, const char *udi) * so this call will fail, and it will actually be added when hal sets the device's * capabilities a bit later on. */ - nm_create_device_and_add_to_list (data, udi); + if ((iface = nm_get_device_interface_from_hal (data->hal_ctx, udi))) + { + nm_create_device_and_add_to_list (data, udi, iface, FALSE, DEVICE_TYPE_DONT_KNOW); + g_free (iface); + } } @@ -237,7 +260,15 @@ static void nm_hal_device_new_capability (LibHalContext *ctx, const char *udi, c syslog( LOG_DEBUG, "nm_hal_device_new_capability() called with udi = %s, capability = %s", udi, capability ); if (capability && (strcmp (capability, "net.ethernet") == 0)) - nm_create_device_and_add_to_list (data, udi); + { + char *iface; + + if ((iface = nm_get_device_interface_from_hal (data->hal_ctx, udi))) + { + nm_create_device_and_add_to_list (data, udi, iface, FALSE, DEVICE_TYPE_DONT_KNOW); + g_free (iface); + } + } } @@ -282,7 +313,15 @@ static void nm_add_initial_devices (NMData *data) if (net_devices) { for (i = 0; i < num_net_devices; i++) - nm_create_device_and_add_to_list (data, net_devices[i]); + { + char *iface; + + if ((iface = nm_get_device_interface_from_hal (data->hal_ctx, net_devices[i]))) + { + nm_create_device_and_add_to_list (data, net_devices[i], iface, FALSE, DEVICE_TYPE_DONT_KNOW); + g_free (iface); + } + } } hal_free_string_array (net_devices); @@ -382,7 +421,7 @@ static LibHalFunctions hal_functions = * Create data structure used in callbacks from libhal. * */ -static NMData *nm_data_new (void) +static NMData *nm_data_new (gboolean enable_test_devices) { NMData *data; @@ -417,6 +456,7 @@ static NMData *nm_data_new (void) } data->state_modified = TRUE; + data->enable_test_devices = enable_test_devices; return (data); } @@ -450,17 +490,17 @@ static void nm_data_free (NMData *data) /* - * nm_data_set_state_modified + * nm_data_mark_state_changed * - * Locked function to protect state modification changes. + * Notify our timeout that the networking state has changed in some way. * */ -void nm_data_set_state_modified (NMData *data, gboolean modified) +void nm_data_mark_state_changed (NMData *data) { g_return_if_fail (data != NULL); g_mutex_lock (data->state_modified_mutex); - data->state_modified = modified; + data->state_modified = TRUE; g_mutex_unlock (data->state_modified_mutex); } @@ -476,8 +516,9 @@ static void nm_print_usage (void) fprintf (stderr, "\n" "usage : NetworkManager [--no-daemon] [--help]\n"); fprintf (stderr, "\n" - " --no-daemon Don't become a daemon\n" - " --help Show this information and exit\n" + " --no-daemon Don't become a daemon\n" + " --enable-test-devices Allow dummy devices to be created via DBUS methods [DEBUG]\n" + " --help Show this information and exit\n" "\n" "NetworkManager monitors all network connections and automatically\n" "chooses the best connection to use. It also allows the user to\n" @@ -493,11 +534,12 @@ static void nm_print_usage (void) */ int main( int argc, char *argv[] ) { - LibHalContext *ctx = NULL; - guint link_source; - guint policy_source; - guint wireless_scan_source; - gboolean become_daemon = TRUE; + LibHalContext *ctx = NULL; + guint link_source; + guint policy_source; + guint wireless_scan_source; + gboolean become_daemon = TRUE; + gboolean enable_test_devices = FALSE; /* Parse options */ while (1) @@ -507,9 +549,10 @@ int main( int argc, char *argv[] ) const char *opt; static struct option options[] = { - {"no-daemon", 0, NULL, 0}, - {"help", 0, NULL, 0}, - {NULL, 0, NULL, 0} + {"no-daemon", 0, NULL, 0}, + {"enable-test-devices", 0, NULL, 0}, + {"help", 0, NULL, 0}, + {NULL, 0, NULL, 0} }; c = getopt_long (argc, argv, "", options, &option_index); @@ -527,6 +570,8 @@ int main( int argc, char *argv[] ) } else if (strcmp (opt, "no-daemon") == 0) become_daemon = FALSE; + else if (strcmp (opt, "enable-test-devices") == 0) + enable_test_devices = TRUE; break; default: @@ -554,7 +599,7 @@ int main( int argc, char *argv[] ) nm_system_load_device_modules (); /* Initialize our instance data */ - nm_data = nm_data_new (); + nm_data = nm_data_new (enable_test_devices); if (!nm_data) { syslog( LOG_CRIT, "nm_data_new() failed... Not enough memory?"); diff --git a/src/NetworkManager.h b/src/NetworkManager.h index d72195210..4f60ff5a0 100644 --- a/src/NetworkManager.h +++ b/src/NetworkManager.h @@ -28,11 +28,12 @@ #include #include "NetworkManagerAP.h" -struct NMData +typedef struct NMData { LibHalContext *hal_ctx; DBusConnection *dbus_connection; gboolean info_daemon_avail; + gboolean enable_test_devices; GSList *dev_list; GMutex *dev_list_mutex; @@ -50,10 +51,24 @@ struct NMData struct NMAccessPointList *trusted_ap_list; struct NMAccessPointList *preferred_ap_list; struct NMAccessPointList *invalid_ap_list; -}; +} NMData; -typedef struct NMData NMData; +/* + * Types of NetworkManager devices + */ +typedef enum NMDeviceType +{ + DEVICE_TYPE_DONT_KNOW = 0, + DEVICE_TYPE_WIRED_ETHERNET, + DEVICE_TYPE_WIRELESS_ETHERNET +} NMDeviceType; -void nm_data_set_state_modified (NMData *data, gboolean modified); + +struct NMDevice *nm_create_device_and_add_to_list (NMData *data, const char *udi, const char *iface, + gboolean test_device, NMDeviceType test_device_type); + +void nm_remove_device_from_list (NMData *data, const char *udi); + +void nm_data_mark_state_changed (NMData *data); #endif diff --git a/src/NetworkManagerAP.c b/src/NetworkManagerAP.c index 5dd7ec8f5..06cba0c38 100644 --- a/src/NetworkManagerAP.c +++ b/src/NetworkManagerAP.c @@ -23,8 +23,6 @@ #include "NetworkManagerUtils.h" #include "NetworkManagerWireless.h" -extern gboolean debug; - /* * Encapsulates Access Point information @@ -32,7 +30,7 @@ extern gboolean debug; struct NMAccessPoint { guint refcount; - gchar *essid; + char *essid; struct ether_addr *address; guint8 quality; double freq; diff --git a/src/NetworkManagerAPList.c b/src/NetworkManagerAPList.c index 54832c39d..68aa104fb 100644 --- a/src/NetworkManagerAPList.c +++ b/src/NetworkManagerAPList.c @@ -26,7 +26,6 @@ #include "NetworkManagerUtils.h" #include "NetworkManagerDbus.h" -extern gboolean debug; struct NMAccessPointList { diff --git a/src/NetworkManagerDbus.c b/src/NetworkManagerDbus.c index 35268fb6e..92c7d7480 100644 --- a/src/NetworkManagerDbus.c +++ b/src/NetworkManagerDbus.c @@ -26,7 +26,6 @@ #include #include -extern gboolean debug; #include "NetworkManager.h" #include "NetworkManagerUtils.h" @@ -36,6 +35,8 @@ extern gboolean debug; #include "NetworkManagerAPList.h" +static int test_dev_num = 0; + /* * nm_dbus_create_error_message * @@ -242,7 +243,7 @@ static DBusMessage *nm_dbus_nm_set_active_device (DBusConnection *connection, DB data->user_device = dev; nm_unlock_mutex (data->user_device_mutex, __FUNCTION__); - nm_data_set_state_modified (data, TRUE); + nm_data_mark_state_changed (data); } return (reply_message); @@ -827,7 +828,7 @@ static DBusHandlerResult nm_dbus_nmi_filter (DBusConnection *connection, DBusMes { data->update_ap_lists = TRUE; data->info_daemon_avail = TRUE; - nm_data_set_state_modified (data, TRUE); + nm_data_mark_state_changed (data); } /* Don't set handled = TRUE since other filter functions on this dbus connection * may want to know about service signals. @@ -844,7 +845,7 @@ static DBusHandlerResult nm_dbus_nmi_filter (DBusConnection *connection, DBusMes { data->update_ap_lists = TRUE; data->info_daemon_avail = FALSE; - nm_data_set_state_modified (data, TRUE); + nm_data_mark_state_changed (data); } /* Don't set handled = TRUE since other filter functions on this dbus connection * may want to know about service signals. @@ -873,7 +874,7 @@ static DBusHandlerResult nm_dbus_nmi_filter (DBusConnection *connection, DBusMes { syslog( LOG_DEBUG, "updating active device's best ap"); nm_device_update_best_ap (data->active_device); - nm_data_set_state_modified (data, TRUE); + nm_data_mark_state_changed (data); syslog( LOG_DEBUG, "Device's best ap now '%s'", nm_ap_get_essid (nm_device_get_best_ap (data->active_device))); } handled = TRUE; @@ -1068,6 +1069,27 @@ static DBusMessage *nm_dbus_devices_handle_request (DBusConnection *connection, "The device cannot see any wireless networks.")); } } + else if (strcmp ("getLinkActive", request) == 0) + dbus_message_append_args (reply_message, DBUS_TYPE_BOOLEAN, nm_device_get_link_active (dev), DBUS_TYPE_INVALID); + else if (strcmp ("setLinkActive", request) == 0) + { + /* Can only set link status for active devices */ + if (nm_device_is_test_device (dev)) + { + DBusError error; + gboolean link; + + dbus_error_init (&error); + if (dbus_message_get_args (message, &error, DBUS_TYPE_BOOLEAN, &link, DBUS_TYPE_INVALID)) + { + nm_device_set_link_active (dev, link); + nm_data_mark_state_changed (data); + } + } + else + reply_message = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "NotTestDevice", + "Only test devices can have their link status set manually."); + } else { /* Must destroy the allocated message */ @@ -1127,7 +1149,7 @@ static DBusHandlerResult nm_dbus_nm_message_handler (DBusConnection *connection, syslog (LOG_DEBUG, "Forcing AP '%s'", nm_ap_get_essid (ap)); nm_device_freeze_best_ap (data->active_device); nm_device_set_best_ap (data->active_device, ap); - nm_data_set_state_modified (data, TRUE); + nm_data_mark_state_changed (data); } dbus_free (network); } @@ -1140,8 +1162,7 @@ static DBusHandlerResult nm_dbus_nm_message_handler (DBusConnection *connection, } else if (strcmp ("status", method) == 0) { - reply_message = dbus_message_new_method_return (message); - if (reply_message) + if ((reply_message = dbus_message_new_method_return (message))) { if (data->active_device && nm_device_activating (data->active_device)) dbus_message_append_args (reply_message, DBUS_TYPE_STRING, "connecting", DBUS_TYPE_INVALID); @@ -1151,6 +1172,64 @@ static DBusHandlerResult nm_dbus_nm_message_handler (DBusConnection *connection, dbus_message_append_args (reply_message, DBUS_TYPE_STRING, "disconnected", DBUS_TYPE_INVALID); } } + else if (strcmp ("createTestDevice", method) == 0) + { + DBusError error; + NMDeviceType type; + + dbus_error_init (&error); + if ( dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &type, DBUS_TYPE_INVALID) + && ((type == DEVICE_TYPE_WIRED_ETHERNET) || (type == DEVICE_TYPE_WIRELESS_ETHERNET))) + { + char *interface = g_strdup_printf ("test%d", test_dev_num); + char *udi = g_strdup_printf ("/test-devices/%s", interface); + NMDevice *dev = NULL; + + dev = nm_create_device_and_add_to_list (data, udi, interface, TRUE, type); + test_dev_num++; + if ((reply_message = dbus_message_new_method_return (message))) + { + char *dev_path = g_strdup_printf ("%s/%s", NM_DBUS_PATH_DEVICES, nm_device_get_iface (dev)); + dbus_message_append_args (reply_message, DBUS_TYPE_STRING, dev_path, DBUS_TYPE_INVALID); + g_free (dev_path); + } + g_free (interface); + g_free (udi); + } + else + reply_message = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "BadType", + "The test device type was invalid."); + } + else if (strcmp ("removeTestDevice", method) == 0) + { + DBusError error; + char *dev_path; + + dbus_error_init (&error); + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &dev_path, DBUS_TYPE_INVALID)) + { + NMDevice *dev; + + if ((dev = nm_dbus_get_device_from_object_path (data, dev_path))) + { + if (nm_device_is_test_device (dev)) + nm_remove_device_from_list (data, nm_device_get_udi (dev)); + else + reply_message = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "NotTestDevice", + "Only test devices can be removed via dbus calls."); + } + else + { + reply_message = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "DeviceNotFound", + "The requested network device does not exist."); + } + } + else + { + reply_message = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "DeviceBad", + "The device ID was bad."); + } + } else handled = FALSE; diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index fd9368595..3f522e73d 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -94,6 +94,9 @@ struct NMDevice gboolean activating; gboolean just_activated; gboolean quit_activation; + + gboolean test_device; + gboolean test_device_up; }; /******************************************************/ @@ -111,7 +114,13 @@ static gboolean nm_device_test_wireless_extensions (NMDevice *dev) iwstats stats; g_return_val_if_fail (dev != NULL, FALSE); - + + /* We obviously cannot probe test devices (since they don't + * actually exist in hardware). + */ + if (dev->test_device) + return (FALSE); + iwlib_socket = iw_sockets_open (); error = iw_get_stats (iwlib_socket, nm_device_get_iface (dev), &stats, NULL, FALSE); close (iwlib_socket); @@ -133,6 +142,11 @@ static gboolean nm_device_supports_wireless_scan (NMDevice *dev) wireless_scan_head scan_data; g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (dev->type == DEVICE_TYPE_WIRELESS_ETHERNET, FALSE); + + /* A test wireless device can always scan (we generate fake scan data for it) */ + if (dev->test_device) + return (TRUE); iwlib_socket = iw_sockets_open (); error = iw_scan (iwlib_socket, nm_device_get_iface (dev), WIRELESS_EXT, &scan_data); @@ -223,16 +237,32 @@ NMDevice *nm_get_device_by_iface (NMData *data, const char *iface) /* * nm_device_new * - * Creates and initializes the structure representation of an NM device. + * Creates and initializes the structure representation of an NM device. For test + * devices, a device type other than DEVICE_TYPE_DONT_KNOW must be specified, this + * argument is ignored for real hardware devices since they are auto-probed. * */ -NMDevice *nm_device_new (const char *iface, NMData *app_data) +NMDevice *nm_device_new (const char *iface, gboolean test_dev, NMDeviceType test_dev_type, NMData *app_data) { NMDevice *dev; g_return_val_if_fail (iface != NULL, NULL); g_return_val_if_fail (strlen (iface) > 0, NULL); + /* Test devices must have a valid type specified */ + if (test_dev && !(test_dev_type != DEVICE_TYPE_DONT_KNOW)) + return (NULL); + + /* Another check to make sure we don't create a test device unless + * test devices were enabled on the command line. + */ + if (app_data && !app_data->enable_test_devices && test_dev) + { + syslog (LOG_ERR, "nm_device_new(): attempt to create a test device, but test devices were not enabled" + " on the command line. Will not create the device.\n"); + return (NULL); + } + dev = g_new0 (NMDevice, 1); if (!dev) { @@ -243,7 +273,15 @@ NMDevice *nm_device_new (const char *iface, NMData *app_data) dev->refcount = 1; dev->app_data = app_data; dev->iface = g_strdup (iface); - dev->type = nm_device_test_wireless_extensions (dev) ? + dev->test_device = test_dev; + + /* Real hardware devices are probed for their type, test devices must have + * their type specified. + */ + if (test_dev) + dev->type = test_dev_type; + else + dev->type = nm_device_test_wireless_extensions (dev) ? DEVICE_TYPE_WIRELESS_ETHERNET : DEVICE_TYPE_WIRED_ETHERNET; if (nm_device_is_wireless (dev)) @@ -409,6 +447,86 @@ gboolean nm_device_get_supports_wireless_scan (NMDevice *dev) } +/* + * nm_device_wireless_link_active + * + * Gets the link state of a wireless device + * + */ +static gboolean nm_device_wireless_link_active (NMDevice *dev) +{ + struct iwreq wrq; + int iwlib_socket; + gboolean link = FALSE; + + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (dev->app_data != NULL, FALSE); + + /* Since non-active wireless cards are supposed to be powered off anyway, + * only scan for active/pending device and clear ap_list and best_ap for + * devices that aren't active/pending. + */ + if (dev != dev->app_data->active_device) + { + nm_ap_list_unref (dev->options.wireless.ap_list); + dev->options.wireless.ap_list = NULL; + if (dev->options.wireless.best_ap) + nm_ap_unref (dev->options.wireless.best_ap); + return (FALSE); + } + + /* Test devices have their link state set through DBUS */ + if (dev->test_device) + return (nm_device_get_link_active (dev)); + + /* FIXME + * For wireless cards, the best indicator of a "link" at this time + * seems to be whether the card has a valid access point MAC address. + * Is there a better way? + */ + iwlib_socket = iw_sockets_open (); + if (iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0) + { + if ( nm_ethernet_address_is_valid ((struct ether_addr *)(&(wrq.u.ap_addr.sa_data))) + && (nm_device_get_best_ap (dev) && !nm_device_need_ap_switch (dev))) + link = TRUE; + } + close (iwlib_socket); + + return (link); +} + + +/* + * nm_device_wired_link_active + * + * Return the link state of a wired device. We usually just grab the HAL + * net.ethernet.link property, but on card insertion we need to check the MII + * registers of the card to get a more accurate response, since HAL may not + * have received a netlink socket link event for the device yet, and therefore + * will return FALSE when the device really does have a link. + * + */ +static gboolean nm_device_wired_link_active (NMDevice *dev, gboolean check_mii) +{ + gboolean link = FALSE; + + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (dev->app_data != NULL, FALSE); + + /* Test devices have their link state set through DBUS */ + if (dev->test_device) + return (nm_device_get_link_active (dev)); + + if (check_mii) + link = mii_get_link (dev); + else if (hal_device_property_exists (dev->app_data->hal_ctx, nm_device_get_udi (dev), "net.ethernet.link")) + link = hal_device_get_property_bool (dev->app_data->hal_ctx, nm_device_get_udi (dev), "net.ethernet.link"); + + return (link); +} + + /* * nm_device_update_link_active * @@ -417,69 +535,30 @@ gboolean nm_device_get_supports_wireless_scan (NMDevice *dev) */ void nm_device_update_link_active (NMDevice *dev, gboolean check_mii) { - gboolean link_active = FALSE; + gboolean link = FALSE; g_return_if_fail (dev != NULL); g_return_if_fail (dev->app_data != NULL); - /* FIXME - * For wireless cards, the best indicator of a "link" at this time - * seems to be whether the card has a valid access point MAC address. - * Is there a better way? - */ switch (nm_device_get_type (dev)) { case DEVICE_TYPE_WIRELESS_ETHERNET: - { - struct iwreq wrq; - int iwlib_socket; - NMData *data = (NMData *)dev->app_data; - - /* Since non-active wireless cards are supposed to be powered off anyway, - * only scan for active/pending device and clear ap_list and best_ap for - * devices that aren't active/pending. - */ - if (dev == data->active_device) - { - iwlib_socket = iw_sockets_open (); - if (iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0) - { - if (nm_ethernet_address_is_valid ((struct ether_addr *)(&(wrq.u.ap_addr.sa_data)))) - if (nm_device_get_best_ap (dev) && !nm_device_need_ap_switch (dev)) - link_active = TRUE; - } - close (iwlib_socket); - } - else - { - nm_ap_list_unref (dev->options.wireless.ap_list); - dev->options.wireless.ap_list = NULL; - if (dev->options.wireless.best_ap) - nm_ap_unref (dev->options.wireless.best_ap); - } + link = nm_device_wireless_link_active (dev); break; - } case DEVICE_TYPE_WIRED_ETHERNET: - { - if (check_mii) - link_active = mii_get_link (dev); - else - if (hal_device_property_exists (dev->app_data->hal_ctx, nm_device_get_udi (dev), "net.ethernet.link")) - link_active = hal_device_get_property_bool (dev->app_data->hal_ctx, nm_device_get_udi (dev), "net.ethernet.link"); - break; - } + link = nm_device_wired_link_active (dev, check_mii); default: - link_active = nm_device_get_link_active (dev); /* Can't get link info for this device, so don't change link status */ + link = nm_device_get_link_active (dev); /* Can't get link info for this device, so don't change link status */ break; } /* Update device link status and global state variable if the status changed */ - if (link_active != nm_device_get_link_active (dev)) + if (link != nm_device_get_link_active (dev)) { - nm_device_set_link_active (dev, link_active); - nm_data_set_state_modified (dev->app_data, TRUE); + nm_device_set_link_active (dev, link); + nm_data_mark_state_changed (dev->app_data); } } @@ -502,6 +581,17 @@ char * nm_device_get_essid (NMDevice *dev) g_return_val_if_fail (dev != NULL, NULL); g_return_val_if_fail (nm_device_is_wireless (dev), NULL); + + /* Test devices return the essid of their "best" access point + * or if there is none, the contents of the cur_essid field. + */ + if (dev->test_device) + { + if (nm_device_get_best_ap (dev)) + return (nm_ap_get_essid (nm_device_get_best_ap (dev))); + else + return (dev->options.wireless.cur_essid); + } iwlib_socket = iw_sockets_open (); if (iwlib_socket >= 0) @@ -541,6 +631,15 @@ void nm_device_set_essid (NMDevice *dev, const char *essid) g_return_if_fail (dev != NULL); g_return_if_fail (nm_device_is_wireless (dev)); + /* Test devices directly set cur_essid */ + if (dev->test_device) + { + if (dev->options.wireless.cur_essid) + g_free (dev->options.wireless.cur_essid); + dev->options.wireless.cur_essid = g_strdup (essid); + return; + } + /* Make sure the essid we get passed is a valid size */ if (!essid) safe_essid[0] = '\0'; @@ -581,7 +680,19 @@ void nm_device_get_ap_address (NMDevice *dev, struct ether_addr *addr) g_return_if_fail (addr != NULL); g_return_if_fail (nm_device_is_wireless (dev)); - /* Do we have a valid MAC address? */ + /* Test devices return an invalid address when there's no link, + * and a made-up address when there is a link. + */ + if (dev->test_device) + { + struct ether_addr good_addr = { {0x70, 0x37, 0x03, 0x70, 0x37, 0x03} }; + struct ether_addr bad_addr = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; + gboolean link = nm_device_get_link_active (dev); + + memcpy ((link ? &good_addr : &bad_addr), &(wrq.u.ap_addr.sa_data), sizeof (struct ether_addr)); + return; + } + iwlib_socket = iw_sockets_open (); if (iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0) memcpy (addr, &(wrq.u.ap_addr.sa_data), sizeof (struct ether_addr)); @@ -612,6 +723,10 @@ void nm_device_set_enc_key (NMDevice *dev, const char *key) g_return_if_fail (dev != NULL); g_return_if_fail (nm_device_is_wireless (dev)); + /* Test devices just ignore encryption keys */ + if (dev->test_device) + return; + /* Make sure the essid we get passed is a valid size */ if (!key) safe_key[0] = '\0'; @@ -625,12 +740,18 @@ void nm_device_set_enc_key (NMDevice *dev, const char *key) if (iwlib_socket >= 0) { wreq.u.data.pointer = (caddr_t) NULL; - wreq.u.data.flags = IW_ENCODE_ENABLED; wreq.u.data.length = 0; + wreq.u.data.flags = IW_ENCODE_ENABLED; + + /* Unfortunately, some drivers (Cisco) don't make a distinction between + * Open System authentication mode and whether or not to use WEP. You + * DON'T have to use WEP when using Open System, but these cards force + * it. Therefore, we have to set Open System mode when using WEP. + */ if (strlen (safe_key) == 0) { - wreq.u.data.flags = IW_ENCODE_OPEN | IW_ENCODE_NOKEY; /* Disable WEP */ + wreq.u.data.flags |= IW_ENCODE_DISABLED | IW_ENCODE_NOKEY; set_key = TRUE; } else @@ -640,6 +761,7 @@ void nm_device_set_enc_key (NMDevice *dev, const char *key) keylen = iw_in_key_full(iwlib_socket, nm_device_get_iface (dev), safe_key, &parsed_key[0], &wreq.u.data.flags); if (keylen > 0) { + wreq.u.data.flags |= IW_ENCODE_OPEN; // FIXME: what about restricted/Shared Key? wreq.u.data.pointer = (caddr_t) &parsed_key; wreq.u.data.length = keylen; set_key = TRUE; @@ -697,6 +819,13 @@ void nm_device_update_ip4_address (NMDevice *dev) g_return_if_fail (dev->app_data != NULL); g_return_if_fail (nm_device_get_iface (dev) != NULL); + /* Test devices get a nice, bogus IP address */ + if (dev->test_device) + { + dev->ip4_address = 0x07030703; + return; + } + socket = nm_get_network_control_socket (); if (socket < 0) return; @@ -747,6 +876,13 @@ static void nm_device_set_up_down (NMDevice *dev, gboolean up) g_return_if_fail (dev != NULL); + /* Test devices do whatever we tell them to do */ + if (dev->test_device) + { + dev->test_device_up = up; + return; + } + iface_fd = nm_get_network_control_socket (); if (iface_fd < 0) return; @@ -801,6 +937,9 @@ gboolean nm_device_is_up (NMDevice *dev) g_return_val_if_fail (dev != NULL, FALSE); + if (dev->test_device) + return (dev->test_device_up); + iface_fd = nm_get_network_control_socket (); if (iface_fd < 0) return (FALSE); @@ -914,6 +1053,32 @@ static gboolean nm_device_activate_wireless (NMDevice *dev) return (success); } + +/* + * nm_device_activation_cancel_if_needed + * + * Check whether we should stop activation, and if so clean up flags + * and other random things. + * + */ +gboolean nm_device_activation_cancel_if_needed (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, TRUE); + + /* If we were told to quit activation, stop the thread and return */ + if (dev->quit_activation) + { + syslog (LOG_DEBUG, "nm_device_activation_worker(%s): activation canceled.", nm_device_get_iface (dev)); + dev->activating = FALSE; + dev->just_activated = FALSE; + nm_device_unref (dev); + return (TRUE); + } + + return (FALSE); +} + + /* * nm_device_activation_worker * @@ -961,8 +1126,7 @@ fprintf( stderr, "(!switch (%d) || !enc_source (%d)) && is_enc (%d)\n", */ if (nm_ap_get_enc_key_source (best_ap) && !nm_ap_get_enc_method_good (best_ap)) { -fprintf (stderr, "trying encryption method\n"); - /* Try another method, since the one set before obviously didn't work */ + /* Try another method, since the one set in a previous iteration obviously didn't work */ switch (nm_ap_get_enc_method (best_ap)) { case (NM_AP_ENC_METHOD_UNKNOWN): @@ -984,26 +1148,20 @@ fprintf (stderr, "trying encryption method\n"); if (ask_for_key) { -fprintf( stderr, "asking for key\n"); dev->options.wireless.user_key_received = FALSE; nm_dbus_get_user_key_for_network (dev->app_data->dbus_connection, dev, best_ap); /* Wait for the key to come back */ + syslog (LOG_DEBUG, "nm_device_activation_worker(%s): asking for user key.", nm_device_get_iface (dev)); while (!dev->options.wireless.user_key_received && !dev->quit_activation) g_usleep (G_USEC_PER_SEC / 2); - syslog (LOG_DEBUG, "nm_device_activation_worker(%s): user key received!", nm_device_get_iface (dev)); + syslog (LOG_DEBUG, "nm_device_activation_worker(%s): user key received.", nm_device_get_iface (dev)); } /* If we were told to quit activation, stop the thread and return */ - if (dev->quit_activation) - { - syslog (LOG_DEBUG, "nm_device_activation_worker(%s): activation canceled 1", nm_device_get_iface (dev)); - dev->activating = FALSE; - dev->just_activated = FALSE; - nm_device_unref (dev); + if (nm_device_activation_cancel_if_needed (dev)) return (NULL); - } } nm_device_activate_wireless (dev); @@ -1015,14 +1173,8 @@ fprintf (stderr, "sleeping due to no access point\n"); } /* If we were told to quit activation, stop the thread and return */ - if (dev->quit_activation) - { - syslog (LOG_DEBUG, "nm_device_activation_worker(%s): activation canceled 1.5", nm_device_get_iface (dev)); - dev->activating = FALSE; - dev->just_activated = FALSE; - nm_device_unref (dev); + if (nm_device_activation_cancel_if_needed (dev)) return (NULL); - } } /* Since we've got a link, the encryption method must be good */ @@ -1070,28 +1222,16 @@ fprintf (stderr, "sleeping due to no access point\n"); sethostname (hostname, strlen (hostname)); /* If we were told to quit activation, stop the thread and return */ - if (dev->quit_activation) - { - syslog (LOG_DEBUG, "nm_device_activation_worker(%s): activation canceled 2", nm_device_get_iface (dev)); - dev->activating = FALSE; - dev->just_activated = FALSE; - nm_device_unref (dev); + if (nm_device_activation_cancel_if_needed (dev)) return (NULL); - } /* Make system aware of any new DNS settings from resolv.conf */ nm_system_update_dns (); } /* If we were told to quit activation, stop the thread and return */ - if (dev->quit_activation) - { - syslog (LOG_DEBUG, "nm_device_activation_worker(%s): activation canceled 3", nm_device_get_iface (dev)); - dev->activating = FALSE; - dev->just_activated = FALSE; - nm_device_unref (dev); + if (nm_device_activation_cancel_if_needed (dev)) return (NULL); - } dev->just_activated = TRUE; syslog (LOG_DEBUG, "nm_device_activation_worker(%s): device activated", nm_device_get_iface (dev)); @@ -1119,8 +1259,8 @@ gboolean nm_device_just_activated (NMDevice *dev) dev->just_activated = FALSE; return (TRUE); } - else - return (FALSE); + + return (FALSE); } @@ -1139,17 +1279,20 @@ gboolean nm_device_activating (NMDevice *dev) /* - * nm_device_activation_cancel + * nm_device_activation_signal_cancel * * Signal activation worker that it should stop and die. * */ -void nm_device_activation_cancel (NMDevice *dev) +void nm_device_activation_signal_cancel (NMDevice *dev) { g_return_if_fail (dev != NULL); - syslog (LOG_DEBUG, "nm_device_activation_cancel(%s): canceled", nm_device_get_iface (dev)); - dev->quit_activation = TRUE; + if (dev->activating) + { + syslog (LOG_DEBUG, "nm_device_activation_signal_cancel(%s): canceled", nm_device_get_iface (dev)); + dev->quit_activation = TRUE; + } } @@ -1164,7 +1307,7 @@ gboolean nm_device_deactivate (NMDevice *dev, gboolean just_added) g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (dev->app_data != NULL, FALSE); - nm_device_activation_cancel (dev); + nm_device_activation_signal_cancel (dev); /* Take out any entries in the routing table and any IP address the old device had. */ nm_system_device_flush_routes (dev); @@ -1235,12 +1378,12 @@ fprintf( stderr, "Got user key\n"); /* - * nm_device_ap_list_add + * nm_device_ap_list_add_ap * * Add an access point to the devices internal AP list. * */ -void nm_device_ap_list_add (NMDevice *dev, NMAccessPoint *ap) +static void nm_device_ap_list_add_ap (NMDevice *dev, NMAccessPoint *ap) { g_return_if_fail (dev != NULL); g_return_if_fail (ap != NULL); @@ -1545,6 +1688,10 @@ static void nm_device_do_normal_scan (NMDevice *dev) g_return_if_fail (dev != NULL); g_return_if_fail (dev->app_data != NULL); + + /* Test devices shouldn't get here since we fake the AP list earlier */ + g_return_if_fail (!dev->test_device); + data = (NMData *)dev->app_data; /* Device must be up before we can scan */ @@ -1637,7 +1784,7 @@ static void nm_device_do_normal_scan (NMDevice *dev) } /* Add the AP to the device's AP list */ - nm_device_ap_list_add (dev, nm_ap); + nm_device_ap_list_add_ap (dev, nm_ap); } tmp_ap = tmp_ap->next; } @@ -1678,6 +1825,9 @@ static void nm_device_do_pseudo_scan (NMDevice *dev) g_return_if_fail (dev != NULL); g_return_if_fail (dev->app_data != NULL); + /* Test devices shouldn't get here since we fake the AP list earlier */ + g_return_if_fail (!dev->test_device); + nm_device_ref (dev); if (!(list = nm_device_ap_list_get (dev))) @@ -1726,7 +1876,7 @@ static void nm_device_do_pseudo_scan (NMDevice *dev) syslog(LOG_INFO, "%s: setting AP '%s' best", nm_device_get_iface (dev), nm_ap_get_essid (ap)); nm_device_set_best_ap (dev, ap); - nm_data_set_state_modified (dev->app_data, TRUE); + nm_data_mark_state_changed (dev->app_data); break; } } @@ -1736,6 +1886,78 @@ static void nm_device_do_pseudo_scan (NMDevice *dev) } +/* + * nm_device_fake_ap_list + * + * Fake the access point list, used for test devices. + * + */ +static void nm_device_fake_ap_list (NMDevice *dev) +{ + #define NUM_FAKE_APS 4 + + int i; + NMAccessPointList *old_ap_list = nm_device_ap_list_get (dev); + + char *fake_essids[NUM_FAKE_APS] = { "green", "bay", "packers", "rule" }; + struct ether_addr fake_addrs[NUM_FAKE_APS] = {{{0x70, 0x37, 0x03, 0x70, 0x37, 0x03}}, + {{0x12, 0x34, 0x56, 0x78, 0x90, 0xab}}, + {{0xcd, 0xef, 0x12, 0x34, 0x56, 0x78}}, + {{0x90, 0xab, 0xcd, 0xef, 0x12, 0x34}} }; + guint8 fake_qualities[NUM_FAKE_APS] = { 150, 26, 200, 100 }; + double fake_freqs[NUM_FAKE_APS] = { 3.1416, 4.1416, 5.1415, 6.1415 }; + gboolean fake_enc[NUM_FAKE_APS] = { FALSE, TRUE, FALSE, TRUE }; + + g_return_if_fail (dev != NULL); + g_return_if_fail (dev->app_data != NULL); + + dev->options.wireless.ap_list = nm_ap_list_new (NETWORK_TYPE_DEVICE); + + for (i = 0; i < NUM_FAKE_APS; i++) + { + NMAccessPoint *nm_ap = nm_ap_new (); + NMAccessPoint *list_ap; + + /* Copy over info from scan to local structure */ + nm_ap_set_essid (nm_ap, fake_essids[i]); + + if (fake_enc[i]) + { + nm_ap_set_encrypted (nm_ap, FALSE); + nm_ap_set_enc_method (nm_ap, NM_AP_ENC_METHOD_NONE); + } + else + { + nm_ap_set_encrypted (nm_ap, TRUE); + nm_ap_set_enc_method (nm_ap, NM_AP_ENC_METHOD_UNKNOWN); + } + + nm_ap_set_address (nm_ap, (const struct ether_addr *)(&fake_addrs[i])); + nm_ap_set_quality (nm_ap, fake_qualities[i]); + nm_ap_set_freq (nm_ap, fake_freqs[i]); + + /* Merge settings from Preferred/Allowed networks, mainly Keys */ + list_ap = nm_ap_list_get_ap_by_essid (dev->app_data->trusted_ap_list, nm_ap_get_essid (nm_ap)); + if (!list_ap) + list_ap = nm_ap_list_get_ap_by_essid (dev->app_data->preferred_ap_list, nm_ap_get_essid (nm_ap)); + if (list_ap) + { + nm_ap_set_timestamp (nm_ap, nm_ap_get_timestamp (list_ap)); + nm_ap_set_enc_key_source (nm_ap, nm_ap_get_enc_key_source (list_ap)); + } + + /* Add the AP to the device's AP list */ + nm_device_ap_list_add_ap (dev, nm_ap); + } + + if (dev == dev->app_data->active_device) + nm_ap_list_diff (dev->app_data, dev, old_ap_list, nm_device_ap_list_get (dev)); + if (old_ap_list) + nm_ap_list_unref (old_ap_list); + +} + + /* * nm_device_do_wireless_scan * @@ -1751,6 +1973,14 @@ void nm_device_do_wireless_scan (NMDevice *dev) if (!nm_try_acquire_mutex (dev->options.wireless.scan_mutex, __FUNCTION__)) return; + /* Compose a fake list of access points */ + if (dev->test_device) + { + nm_device_fake_ap_list (dev); + nm_unlock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__); + return; + } + if (nm_device_get_supports_wireless_scan (dev)) nm_device_do_normal_scan (dev); else @@ -1859,3 +2089,19 @@ static gboolean mii_get_link (NMDevice *dev) /****************************************/ /* End Code ripped from HAL */ /****************************************/ + + +/****************************************/ +/* Test device routes */ +/****************************************/ + +/* + * nm_device_is_test_device + * + */ +gboolean nm_device_is_test_device (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return (dev->test_device); +} diff --git a/src/NetworkManagerDevice.h b/src/NetworkManagerDevice.h index 930c7260f..a0f6c5d38 100644 --- a/src/NetworkManagerDevice.h +++ b/src/NetworkManagerDevice.h @@ -25,85 +25,76 @@ #include #include "NetworkManager.h" -/* - * Types of NetworkManager devices - */ -enum NMDeviceType -{ - DEVICE_TYPE_DONT_KNOW = 0, - DEVICE_TYPE_WIRED_ETHERNET, - DEVICE_TYPE_WIRELESS_ETHERNET -}; +typedef struct NMDevice NMDevice; -typedef struct NMDevice NMDevice; -typedef enum NMDeviceType NMDeviceType; +NMDevice * nm_device_new (const char *iface, gboolean test_device, + NMDeviceType test_dev_type, NMData *app_data); +void nm_device_ref (NMDevice *dev); +void nm_device_unref (NMDevice *dev); -NMDevice * nm_device_new (const char *iface, NMData *app_data); +char * nm_device_get_udi (NMDevice *dev); +void nm_device_set_udi (NMDevice *dev, const char *udi); -void nm_device_ref (NMDevice *dev); -void nm_device_unref (NMDevice *dev); +char * nm_device_get_iface (NMDevice *dev); -char * nm_device_get_udi (NMDevice *dev); -void nm_device_set_udi (NMDevice *dev, const char *udi); - -char * nm_device_get_iface (NMDevice *dev); - -NMDeviceType nm_device_get_type (NMDevice *dev); -gboolean nm_device_is_wireless (NMDevice *dev); -gboolean nm_device_is_wired (NMDevice *dev); +NMDeviceType nm_device_get_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); -void nm_device_set_link_active (NMDevice *dev, const gboolean active); -void nm_device_update_link_active (NMDevice *dev, gboolean check_mii); +gboolean nm_device_get_link_active (NMDevice *dev); +void nm_device_set_link_active (NMDevice *dev, const gboolean active); +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); +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); +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); +guint32 nm_device_get_ip4_address (NMDevice *dev); +void nm_device_update_ip4_address (NMDevice *dev); -void nm_device_get_ip6_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); -guint8 nm_device_get_max_quality (NMDevice *dev); +void nm_device_do_wireless_scan (NMDevice *dev); +guint8 nm_device_get_max_quality (NMDevice *dev); -NMAccessPoint *nm_device_get_best_ap (NMDevice *dev); -void nm_device_set_best_ap (NMDevice *dev, NMAccessPoint *ap); -void nm_device_update_best_ap (NMDevice *dev); -gboolean nm_device_need_ap_switch (NMDevice *dev); -void nm_device_freeze_best_ap (NMDevice *dev); -void nm_device_unfreeze_best_ap (NMDevice *dev); -gboolean nm_device_get_best_ap_frozen (NMDevice *dev); +NMAccessPoint *nm_device_get_best_ap (NMDevice *dev); +void nm_device_set_best_ap (NMDevice *dev, NMAccessPoint *ap); +void nm_device_update_best_ap (NMDevice *dev); +gboolean nm_device_need_ap_switch (NMDevice *dev); +void nm_device_freeze_best_ap (NMDevice *dev); +void nm_device_unfreeze_best_ap (NMDevice *dev); +gboolean nm_device_get_best_ap_frozen (NMDevice *dev); -char * nm_device_get_path_for_ap (NMDevice *dev, NMAccessPoint *ap); +char * nm_device_get_path_for_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_enc_key (NMDevice *dev, const char *key); +void nm_device_set_enc_key (NMDevice *dev, const char *key); -gboolean nm_device_activation_begin (NMDevice *dev); -void nm_device_activation_cancel (NMDevice *dev); -gboolean nm_device_just_activated (NMDevice *dev); -gboolean nm_device_activating (NMDevice *dev); -gboolean nm_device_deactivate (NMDevice *dev, gboolean just_added); +gboolean nm_device_activation_begin (NMDevice *dev); +void nm_device_activation_signal_cancel (NMDevice *dev); +gboolean nm_device_just_activated (NMDevice *dev); +gboolean nm_device_activating (NMDevice *dev); +gboolean nm_device_deactivate (NMDevice *dev, gboolean just_added); void nm_device_set_user_key_for_network (NMDevice *dev, struct NMAccessPointList *invalid_list, unsigned char *network, unsigned char *key); -void nm_device_bring_up (NMDevice *dev); -void nm_device_bring_down (NMDevice *dev); -gboolean nm_device_is_up (NMDevice *dev); +void nm_device_bring_up (NMDevice *dev); +void nm_device_bring_down (NMDevice *dev); +gboolean nm_device_is_up (NMDevice *dev); -void nm_device_ap_list_add (NMDevice *dev, NMAccessPoint *ap); -void nm_device_ap_list_clear (NMDevice *dev); +void nm_device_ap_list_clear (NMDevice *dev); struct NMAccessPointList *nm_device_ap_list_get (NMDevice *dev); NMAccessPoint *nm_device_ap_list_get_ap_by_essid (NMDevice *dev, const char *essid); -NMDevice * nm_get_device_by_udi (NMData *data, const char *udi); -NMDevice * nm_get_device_by_iface (NMData *data, const char *iface); +NMDevice * nm_get_device_by_udi (NMData *data, const char *udi); +NMDevice * nm_get_device_by_iface (NMData *data, const char *iface); + +/* Test device routines */ +gboolean nm_device_is_test_device (NMDevice *dev); #endif diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 113231d44..385d30ce5 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -36,7 +36,6 @@ #include "NetworkManagerDbus.h" gboolean allowed_ap_worker_exit = FALSE; -extern gboolean debug; /* @@ -173,7 +172,9 @@ static NMDevice * nm_policy_get_best_device (NMData *data) nm_unlock_mutex (data->user_device_mutex, __FUNCTION__); } - /* Determine whether we need to clear the active device and unlock it. */ + /* Determine whether we need to clear the active device and unlock it. + * This occurs if the best device is removed, for example. + */ if (!best_dev && data->active_device_locked) { switch (nm_device_get_type (data->active_device)) @@ -198,6 +199,22 @@ static NMDevice * nm_policy_get_best_device (NMData *data) } } + /* Or, if the current active device is wireless and its "best" access + * point is locked, use that device still. This happens when the user + * forces a specific wireless network choice. The "best" ap will have + * already been set and locked by the dbus message handler, so we just + * need to test for a locked "best" ap. + */ + if (data->active_device && nm_device_is_wireless (data->active_device)) + { + /* Give ourselves a chance to clear the "best" access point if + * its gone out of range and no longer in the device's ap list. + */ + nm_device_update_best_ap (data->active_device); + if (nm_device_get_best_ap_frozen (data->active_device)) + best_dev = data->active_device; + } + /* Fall back to automatic device picking */ if (!best_dev) { @@ -276,8 +293,6 @@ gboolean nm_state_modification_monitor (gpointer user_data) || ( best_dev && nm_device_is_wireless (best_dev) && !nm_device_activating (best_dev) && (nm_device_need_ap_switch (best_dev) || (nm_device_get_ip4_address (best_dev) == 0)))) { - syslog (LOG_INFO, "nm_state_modification_monitor(): beginning activation for device '%s'", best_dev ? nm_device_get_iface (best_dev) : "(null)"); - /* Deactivate the old device */ if (data->active_device) { @@ -286,10 +301,14 @@ gboolean nm_state_modification_monitor (gpointer user_data) data->active_device = NULL; } - /* Begin activation on the new device */ - nm_device_ref (best_dev); - data->active_device = best_dev; - nm_device_activation_begin (data->active_device); + if (best_dev) + { + /* Begin activation on the new device */ + syslog (LOG_INFO, "nm_state_modification_monitor(): beginning activation for device '%s'", nm_device_get_iface (best_dev)); + nm_device_ref (best_dev); + data->active_device = best_dev; + nm_device_activation_begin (data->active_device); + } } nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 2f39fa483..e392ab4c2 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -28,8 +28,6 @@ #include "NetworkManager.h" #include "NetworkManagerUtils.h" -extern gboolean debug; - /*#define LOCKING_DEBUG */ diff --git a/src/NetworkManagerWireless.c b/src/NetworkManagerWireless.c index 730f6585f..5bdaa7117 100644 --- a/src/NetworkManagerWireless.c +++ b/src/NetworkManagerWireless.c @@ -33,7 +33,6 @@ #include "NetworkManagerPolicy.h" #include "NetworkManagerUtils.h" -extern gboolean debug; static char * nm_md5 (const char *buf, size_t len) diff --git a/src/backends/NetworkManagerDebian.c b/src/backends/NetworkManagerDebian.c index 9dce91fc3..c7489096d 100644 --- a/src/backends/NetworkManagerDebian.c +++ b/src/backends/NetworkManagerDebian.c @@ -47,6 +47,13 @@ gboolean nm_system_device_run_dhcp (NMDevice *dev) g_return_val_if_fail (dev != NULL, FALSE); + /* Fake it for a test device */ + if (nm_device_is_test_device (dev)) + { + g_usleep (2000); + return (TRUE); + } + /* 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). */ @@ -74,6 +81,10 @@ void nm_system_device_stop_dhcp (NMDevice *dev) g_return_if_fail (dev != NULL); + /* Not really applicable for test devices */ + if (nm_device_is_test_device (dev)) + return; + /* Find and kill the previous dhclient process for this device */ snprintf (buf, 500, "/var/run/dhclient-%s.pid", nm_device_get_iface (dev)); pidfile = fopen (buf, "r"); @@ -107,6 +118,10 @@ void nm_system_device_flush_routes (NMDevice *dev) g_return_if_fail (dev != NULL); + /* Not really applicable for test devices */ + if (nm_device_is_test_device (dev)) + return; + /* Remove routing table entries */ snprintf (buf, 100, "/sbin/ip route flush dev %s", nm_device_get_iface (dev)); nm_spawn_process (buf); @@ -125,7 +140,11 @@ void nm_system_device_flush_addresses (NMDevice *dev) g_return_if_fail (dev != NULL); - /* Remove routing table entries */ + /* Not really applicable for test devices */ + if (nm_device_is_test_device (dev)) + return; + + /* Remove all IP addresses for a device */ snprintf (buf, 100, "/sbin/ip address flush dev %s", nm_device_get_iface (dev)); nm_spawn_process (buf); } diff --git a/src/backends/NetworkManagerGentoo.c b/src/backends/NetworkManagerGentoo.c index 5fa722c86..30e65b827 100644 --- a/src/backends/NetworkManagerGentoo.c +++ b/src/backends/NetworkManagerGentoo.c @@ -64,6 +64,13 @@ gboolean nm_system_device_run_dhcp (NMDevice *dev) g_return_val_if_fail (dev != NULL, FALSE); + /* Fake it for a test device */ + if (nm_device_is_test_device (dev)) + { + g_usleep (2000); + return (TRUE); + } + iface = nm_device_get_iface (dev); snprintf (buf, 500, "/sbin/dhcpcd %s", iface); err = nm_spawn_process (buf); @@ -85,6 +92,10 @@ void nm_system_device_stop_dhcp (NMDevice *dev) g_return_if_fail (dev != NULL); + /* Not really applicable for test devices */ + if (nm_device_is_test_device (dev)) + return; + snprintf (buf, 500, "/var/run/dhcpcd-%s.pid", nm_device_get_iface(dev)); pidfile = fopen (buf, "r"); if (pidfile) @@ -116,11 +127,15 @@ void nm_system_device_flush_routes (NMDevice *dev) g_return_if_fail (dev != NULL); + /* Not really applicable for test devices */ + if (nm_device_is_test_device (dev)) + return; + if (nm_system_gentoo_conf_type == GENTOO_CONF_TYPE_IPROUTE) { snprintf (buf, 100, "/sbin/ip route flush dev %s", nm_device_get_iface (dev)); } else if (nm_system_gentoo_conf_type == GENTOO_CONF_TYPE_IFCONFIG) { // FIXME: this command still isn't right - snprintf (buf, 100, "/sbin/route del dev%s", nm_device_get_iface (dev)); + snprintf (buf, 100, "/sbin/route del dev %s", nm_device_get_iface (dev)); } else { snprintf (buf, 100, "/bin/false"); } @@ -139,6 +154,10 @@ void nm_system_device_flush_addresses (NMDevice *dev) g_return_if_fail (dev != NULL); + /* Not really applicable for test devices */ + if (nm_device_is_test_device (dev)) + return; + if (nm_system_gentoo_conf_type == GENTOO_CONF_TYPE_IPROUTE) { snprintf (buf, 100, "/sbin/ip address flush dev %s", nm_device_get_iface (dev)); } else if (nm_system_gentoo_conf_type == GENTOO_CONF_TYPE_IFCONFIG) { diff --git a/src/backends/NetworkManagerRedHat.c b/src/backends/NetworkManagerRedHat.c index 326abb978..8dc05c145 100644 --- a/src/backends/NetworkManagerRedHat.c +++ b/src/backends/NetworkManagerRedHat.c @@ -54,6 +54,13 @@ gboolean nm_system_device_run_dhcp (NMDevice *dev) g_return_val_if_fail (dev != NULL, FALSE); + /* Fake it for a test device */ + if (nm_device_is_test_device (dev)) + { + g_usleep (2000); + return (TRUE); + } + /* 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). */ @@ -80,6 +87,10 @@ void nm_system_device_stop_dhcp (NMDevice *dev) g_return_if_fail (dev != NULL); + /* Not really applicable for test devices */ + if (nm_device_is_test_device (dev)) + return; + /* Find and kill the previous dhclient process for this device */ snprintf (buf, 500, "/var/run/dhclient-%s.pid", nm_device_get_iface (dev)); pidfile = fopen (buf, "r"); @@ -113,6 +124,10 @@ void nm_system_device_flush_routes (NMDevice *dev) g_return_if_fail (dev != NULL); + /* Not really applicable for test devices */ + if (nm_device_is_test_device (dev)) + return; + /* Remove routing table entries */ snprintf (buf, 100, "/sbin/ip route flush dev %s", nm_device_get_iface (dev)); nm_spawn_process (buf); @@ -131,7 +146,11 @@ void nm_system_device_flush_addresses (NMDevice *dev) g_return_if_fail (dev != NULL); - /* Remove routing table entries */ + /* Not really applicable for test devices */ + if (nm_device_is_test_device (dev)) + return; + + /* Remove all IP addresses for a device */ snprintf (buf, 100, "/sbin/ip address flush dev %s", nm_device_get_iface (dev)); nm_spawn_process (buf); } @@ -170,7 +189,7 @@ void nm_system_delete_default_route (void) */ void nm_system_kill_all_dhcp_daemons (void) { - nm_spawn_process ("/usr/bin/killall dhclient"); + nm_spawn_process ("/usr/bin/killall -q dhclient"); } @@ -183,7 +202,8 @@ void nm_system_kill_all_dhcp_daemons (void) */ void nm_system_update_dns (void) { - nm_spawn_process ("/sbin/service nscd restart"); + if(nm_spawn_process ("/etc/init.d/nscd status")) + nm_spawn_process ("/etc/init.d/nscd restart"); } diff --git a/test/Makefile.am b/test/Makefile.am index 854f688d2..454947559 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -4,10 +4,13 @@ INCLUDES = \ -DBINDIR=\"$(bindir)\" \ -DDATADIR=\"$(datadir)\" -noinst_PROGRAMS = nmtest nminfotest +noinst_PROGRAMS = nmtest nminfotest nmtestdevices nmtest_SOURCES = nmclienttest.c nmtest_LDADD = $(NM_LIBS) nminfotest_SOURCES = nminfotest.c nminfotest_LDADD = $(NM_LIBS) + +nmtestdevices_SOURCES = nmtestdevices.c +nmtestdevices_LDADD = $(NM_LIBS) diff --git a/test/nmtestdevices.c b/test/nmtestdevices.c new file mode 100644 index 000000000..713e4bb36 --- /dev/null +++ b/test/nmtestdevices.c @@ -0,0 +1,297 @@ +/* nmtestdevices - Tool to create/delete/modify test devices for NetworkManager + * (use when you are on a plane, don't have a wireless card, etc) + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2004 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include + +/* These MUST correspond to NetworkManager device types */ +typedef enum NMDeviceType +{ + DEVICE_TYPE_DONT_KNOW = 0, + DEVICE_TYPE_WIRED_ETHERNET, + DEVICE_TYPE_WIRELESS_ETHERNET +} NMDeviceType; + + +#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" +#define NM_DBUS_PATH "/org/freedesktop/NetworkManager" +#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" +#define NM_DBUS_INTERFACE_DEVICES "org.freedesktop.NetworkManager.Devices" + + +void create_device (DBusConnection *connection, NMDeviceType type) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + DBusError error; + + g_return_if_fail (connection != NULL); + g_return_if_fail (((type == DEVICE_TYPE_WIRED_ETHERNET) || (type == DEVICE_TYPE_WIRELESS_ETHERNET))); + + message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "createTestDevice"); + if (message == NULL) + { + fprintf (stderr, "Couldn't allocate the dbus message\n"); + return; + } + + dbus_error_init (&error); + dbus_message_append_args (message, DBUS_TYPE_INT32, type, DBUS_TYPE_INVALID); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + if (dbus_error_is_set (&error)) + { + fprintf (stderr, "%s raised:\n %s\n\n", error.name, error.message); + dbus_error_free (&error); + dbus_message_unref (message); + return; + } + + if (reply == NULL) + { + fprintf( stderr, "dbus reply message was NULL\n" ); + dbus_message_unref (message); + return; + } + + /* now analyze reply */ + dbus_message_iter_init (reply, &iter); + char *string; + string = dbus_message_iter_get_string (&iter); + if (!string) + { + fprintf (stderr, "NetworkManager returned a NULL test device ID, test device could not be created." ); + return; + } + + fprintf (stderr, "New test device ID: '%s'\n", string ); + + dbus_free (string); + dbus_message_unref (reply); + dbus_message_unref (message); +} + + +void remove_device (DBusConnection *connection, char *dev) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + DBusError error; + + g_return_if_fail (connection != NULL); + g_return_if_fail (dev != NULL); + + message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "removeTestDevice"); + if (message == NULL) + { + fprintf (stderr, "Couldn't allocate the dbus message\n"); + return; + } + + dbus_error_init (&error); + dbus_message_append_args (message, DBUS_TYPE_STRING, dev, DBUS_TYPE_INVALID); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + if (dbus_error_is_set (&error)) + { + fprintf (stderr, "%s raised:\n %s\n\n", error.name, error.message); + dbus_error_free (&error); + dbus_message_unref (message); + return; + } + + if (reply == NULL) + { + fprintf( stderr, "dbus reply message was NULL\n" ); + dbus_message_unref (message); + return; + } + + dbus_message_unref (message); + dbus_message_unref (reply); +} + + +void set_link_active (DBusConnection *connection, char *dev, gboolean active) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + DBusError error; + + g_return_if_fail (connection != NULL); + g_return_if_fail (dev != NULL); + + message = dbus_message_new_method_call (NM_DBUS_SERVICE, dev, NM_DBUS_INTERFACE_DEVICES, "setLinkActive"); + if (message == NULL) + { + fprintf (stderr, "Couldn't allocate the dbus message\n"); + return; + } + + dbus_message_append_args (message, DBUS_TYPE_BOOLEAN, active, DBUS_TYPE_INVALID); + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + if (dbus_error_is_set (&error)) + { + fprintf (stderr, "%s raised:\n %s\n\n", error.name, error.message); + dbus_error_free (&error); + dbus_message_unref (message); + return; + } + + if (reply == NULL) + { + fprintf( stderr, "dbus reply message was NULL\n" ); + dbus_message_unref (message); + return; + } + + dbus_message_unref (message); + dbus_message_unref (reply); +} + + +static void print_usage (void) +{ + fprintf (stderr, "\n" "usage : nmtestdevices [options] [--help]\n"); + fprintf (stderr, + "\n" + " --create-device Creates a test device, returns the new device ID\n" + " --remove-device Remove a test device (cannot remove real devices)\n" + " --make-link-active Switch a test device's link ON\n" + " --make-link-inactive Switch a test device's link OFF\n" + " --help Show this information and exit\n" + "\n" + "This tool allows you to tell NetworkManager to create and manipulate fake 'test' devices. This\n" + "is useful in sitation where you may not have a particular device but still want to test\n" + "NetworkManager out with it (For example, you forgot your wireless card at home and now you're\n" + "taking a trip and want to hack on NM, and you're on a plane so you could use the wireless\n" + "card anyway).\n" + "\n"); +} + + +int main( int argc, char *argv[] ) +{ + DBusConnection *connection; + DBusError error; + char *dev = NULL; + gboolean create = FALSE; + gboolean remove = FALSE; + gboolean make_link_active = FALSE; + gboolean make_link_inactive = FALSE; + NMDeviceType dev_type = DEVICE_TYPE_DONT_KNOW; + + /* Parse options */ + while (1) + { + int c; + int option_index = 0; + const char *opt; + + static struct option options[] = { + {"create-device", 1, NULL, 0}, + {"remove-device", 1, NULL, 0}, + {"make-link-active", 1, NULL, 0}, + {"make-link-inactive", 1, NULL, 0}, + {"help", 0, NULL, 0}, + {NULL, 0, NULL, 0} + }; + + c = getopt_long (argc, argv, "", options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + opt = options[option_index].name; + if (strcmp (opt, "help") == 0) + { + print_usage (); + exit (0); + } + else if (strcmp (opt, "create-device") == 0) + { + create = TRUE; + if (optarg) + { + if (strcmp (optarg, "wired") == 0) + dev_type = DEVICE_TYPE_WIRED_ETHERNET; + else if (strcmp (optarg, "wireless") == 0) + dev_type = DEVICE_TYPE_WIRELESS_ETHERNET; + } + } + else if (strcmp (opt, "remove-device") == 0) + { + remove = TRUE; + if (optarg) + dev = g_strdup (optarg); + } + else if (strcmp (opt, "make-link-active") == 0) + { + make_link_active = TRUE; + if (optarg) + dev = g_strdup (optarg); + } + else if (strcmp (opt, "make-link-inactive") == 0) + { + make_link_inactive = TRUE; + if (optarg) + dev = g_strdup (optarg); + } + break; + + default: + print_usage (); + exit (1); + break; + } + } + + g_type_init (); + + dbus_error_init (&error); + connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error); + if (connection == NULL) + { + fprintf (stderr, "Error connecting to system bus: %s\n", error.message); + dbus_error_free (&error); + return 1; + } + + if (create) + create_device (connection, dev_type); + else if (remove) + remove_device (connection, dev); + else if (make_link_active) + set_link_active (connection, dev, TRUE); + else if (make_link_inactive) + set_link_active (connection, dev, FALSE); + + return 0; +}