summaryrefslogtreecommitdiff
path: root/src/NetworkManagerDevice.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/NetworkManagerDevice.c')
-rw-r--r--src/NetworkManagerDevice.c348
1 files changed, 256 insertions, 92 deletions
diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c
index 9c52a21a08..dae40d325e 100644
--- a/src/NetworkManagerDevice.c
+++ b/src/NetworkManagerDevice.c
@@ -52,6 +52,9 @@ static gboolean supports_mii_carrier_detect (NMDevice *dev);
static gboolean supports_ethtool_carrier_detect (NMDevice *dev);
static gboolean nm_device_bring_up_wait (NMDevice *dev, gboolean cancelable);
static gboolean link_to_specific_ap (NMDevice *dev, NMAccessPoint *ap, gboolean default_link);
+static guint32 nm_device_discover_capabilities (NMDevice *dev);
+static gboolean nm_is_driver_supported (NMDevice *dev);
+static guint32 nm_device_wireless_discover_capabilities (NMDevice *dev);
static void nm_device_activate_schedule_stage1_device_prepare (NMActRequest *req);
static void nm_device_activate_schedule_stage2_device_config (NMActRequest *req);
@@ -114,34 +117,65 @@ static gboolean nm_device_test_wireless_extensions (NMDevice *dev)
/*
- * nm_device_supports_wireless_scan
+ * nm_get_device_driver_name
*
- * Test whether a given device is a wireless one or not.
+ * Get the device's driver name from HAL.
*
*/
-static gboolean nm_device_supports_wireless_scan (NMDevice *dev)
+static char *nm_get_device_driver_name (NMDevice *dev)
{
- NMSock *sk;
- int err;
- gboolean can_scan = TRUE;
- wireless_scan_head scan_data;
-
- g_return_val_if_fail (dev != NULL, FALSE);
- g_return_val_if_fail (dev->type == DEVICE_TYPE_WIRELESS_ETHERNET, FALSE);
+ char * udi = NULL;
+ char * driver_name = NULL;
+ LibHalContext *ctx = NULL;
- /* A test wireless device can always scan (we generate fake scan data for it) */
- if (dev->test_device)
- return (TRUE);
+ g_return_val_if_fail (dev != NULL, NULL);
+ g_return_val_if_fail (dev->app_data != NULL, NULL);
- if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL)))
+ ctx = dev->app_data->hal_ctx;
+ g_return_val_if_fail (ctx != NULL, NULL);
+
+ if ((udi = nm_device_get_udi (dev)))
{
- err = iw_scan (nm_dev_sock_get_fd (sk), (char *)nm_device_get_iface (dev), WIRELESS_EXT, &scan_data);
- nm_dispose_scan_results (scan_data.result);
- if ((err == -1) && (errno == EOPNOTSUPP))
- can_scan = FALSE;
- nm_dev_sock_close (sk);
+ char *parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
+
+ if (parent_udi && libhal_device_property_exists (ctx, parent_udi, "info.linux.driver", NULL))
+ {
+ char *drv = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL);
+ driver_name = g_strdup (drv);
+ g_free (drv);
+ }
+ g_free (parent_udi);
}
- return (can_scan);
+
+ return driver_name;
+}
+
+/* Blacklist of unsupported drivers */
+static char * driver_blacklist[] =
+{
+ NULL
+};
+
+
+/*
+ * nm_is_driver_supported
+ *
+ * Check device's driver against a blacklist of unsupported drivers.
+ *
+ */
+static gboolean nm_is_driver_supported (NMDevice *dev)
+{
+ char ** drv = NULL;
+
+ g_return_val_if_fail (dev != NULL, FALSE);
+ g_return_val_if_fail (dev->driver != NULL, FALSE);
+
+ for (drv = &driver_blacklist[0]; *drv; drv++)
+ {
+ if (!strcmp (*drv, dev->driver))
+ return FALSE;
+ }
+ return TRUE;
}
@@ -259,6 +293,64 @@ void nm_device_copy_allowed_to_dev_list (NMDevice *dev, NMAccessPointList *allow
/*
+ * nm_device_wireless_init
+ *
+ * Initialize a new wireless device with wireless-specific settings.
+ *
+ */
+static gboolean nm_device_wireless_init (NMDevice *dev)
+{
+ NMSock *sk;
+ NMDeviceWirelessOptions *opts = &(dev->options.wireless);
+
+ g_return_val_if_fail (dev != NULL, FALSE);
+ g_return_val_if_fail (nm_device_is_wireless (dev), FALSE);
+
+ opts->scan_mutex = g_mutex_new ();
+ opts->ap_list = nm_ap_list_new (NETWORK_TYPE_DEVICE);
+ if (!opts->scan_mutex || !opts->ap_list)
+ return FALSE;
+
+ nm_register_mutex_desc (opts->scan_mutex, "Scan Mutex");
+ nm_wireless_set_scan_interval (dev->app_data, dev, NM_WIRELESS_SCAN_INTERVAL_ACTIVE);
+
+ nm_device_set_mode (dev, NETWORK_MODE_INFRA);
+
+ /* Non-scanning devices show the entire allowed AP list as their
+ * available networks.
+ */
+ if (!(dev->capabilities & NM_DEVICE_CAP_WIRELESS_SCAN))
+ nm_device_copy_allowed_to_dev_list (dev, dev->app_data->allowed_ap_list);
+
+ if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL)))
+ {
+ iwrange range;
+ if (iw_get_range_info (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), &range) >= 0)
+ {
+ int i;
+
+ opts->max_qual.qual = range.max_qual.qual;
+ opts->max_qual.level = range.max_qual.level;
+ opts->max_qual.noise = range.max_qual.noise;
+ opts->max_qual.updated = range.max_qual.updated;
+
+ opts->avg_qual.qual = range.avg_qual.qual;
+ opts->avg_qual.level = range.avg_qual.level;
+ opts->avg_qual.noise = range.avg_qual.noise;
+ opts->avg_qual.updated = range.avg_qual.updated;
+
+ opts->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES);
+ for (i = 0; i < opts->num_freqs; i++)
+ opts->freqs[i] = iw_freq2float (&(range.freq[i]));
+ }
+ nm_dev_sock_close (sk);
+ }
+
+ return TRUE;
+}
+
+
+/*
* nm_device_new
*
* Creates and initializes the structure representation of an NM device. For test
@@ -296,7 +388,8 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev,
dev->app_data = app_data;
dev->iface = g_strdup (iface);
dev->test_device = test_dev;
- nm_device_set_udi (dev, udi);
+ dev->udi = g_strdup (udi);
+ dev->driver = nm_get_device_driver_name (dev);
dev->use_dhcp = TRUE;
/* Real hardware devices are probed for their type, test devices must have
@@ -318,66 +411,19 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev,
/* Have to bring the device up before checking link status and other stuff */
nm_device_bring_up_wait (dev, 0);
- /* Initialize wireless-specific options */
- if (nm_device_is_wireless (dev))
- {
- NMSock *sk;
- NMDeviceWirelessOptions *opts = &(dev->options.wireless);
-
- nm_device_set_mode (dev, NETWORK_MODE_INFRA);
-
- nm_wireless_set_scan_interval (dev->app_data, dev, NM_WIRELESS_SCAN_INTERVAL_ACTIVE);
-
- opts->scan_mutex = g_mutex_new ();
- opts->ap_list = nm_ap_list_new (NETWORK_TYPE_DEVICE);
- if (!opts->scan_mutex || !opts->ap_list)
- goto err;
-
- nm_register_mutex_desc (opts->scan_mutex, "Scan Mutex");
-
- opts->supports_wireless_scan = nm_device_supports_wireless_scan (dev);
-
- /* Non-scanning devices show the entire allowed AP list as their
- * available networks.
- */
- if (opts->supports_wireless_scan == FALSE)
- nm_device_copy_allowed_to_dev_list (dev, app_data->allowed_ap_list);
-
- if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL)))
- {
- iwrange range;
- if (iw_get_range_info (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), &range) >= 0)
- {
- int i;
-
- opts->max_qual.qual = range.max_qual.qual;
- opts->max_qual.level = range.max_qual.level;
- opts->max_qual.noise = range.max_qual.noise;
- opts->max_qual.updated = range.max_qual.updated;
-
- opts->avg_qual.qual = range.avg_qual.qual;
- opts->avg_qual.level = range.avg_qual.level;
- opts->avg_qual.noise = range.avg_qual.noise;
- opts->avg_qual.updated = range.avg_qual.updated;
+ /* First check for driver support */
+ if (nm_is_driver_supported (dev))
+ dev->capabilities |= NM_DEVICE_CAP_NM_SUPPORTED;
- opts->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES);
- for (i = 0; i < opts->num_freqs; i++)
- opts->freqs[i] = iw_freq2float (&(range.freq[i]));
- }
- nm_dev_sock_close (sk);
- }
- }
- else if (nm_device_is_wired (dev))
+ /* Then discover devices-specific capabilities */
+ if (dev->capabilities & NM_DEVICE_CAP_NM_SUPPORTED)
{
- if (supports_ethtool_carrier_detect (dev) || supports_mii_carrier_detect (dev))
- dev->options.wired.has_carrier_detect = TRUE;
- }
+ dev->capabilities |= nm_device_discover_capabilities (dev);
- /* Must be called after carrier detect or wireless scan detect. */
- dev->driver_support_level = nm_get_driver_support_level (dev->app_data->hal_ctx, dev);
+ /* Initialize wireless-specific options */
+ if (nm_device_is_wireless (dev) && !nm_device_wireless_init (dev))
+ goto err;
- if (nm_device_get_driver_support_level (dev) != NM_DRIVER_UNSUPPORTED)
- {
nm_device_set_link_active (dev, nm_device_probe_link_state (dev));
nm_device_update_ip4_address (dev);
nm_device_update_hw_address (dev);
@@ -387,6 +433,8 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev,
dev->use_dhcp = nm_system_device_get_use_dhcp (dev);
}
+ nm_print_device_capabilities (dev);
+
dev->worker = g_thread_create (nm_device_worker, dev, TRUE, &error);
if (!dev->worker)
{
@@ -463,6 +511,7 @@ gboolean nm_device_unref (NMDevice *dev)
g_free (dev->udi);
g_free (dev->iface);
+ g_free (dev->driver);
memset (dev, 0, sizeof (NMDevice));
g_free (dev);
deleted = TRUE;
@@ -536,6 +585,105 @@ void nm_device_worker_thread_stop (NMDevice *dev)
/*
+ * nm_device_wireless_discover_capabilities
+ *
+ * Figure out wireless-specific capabilities
+ *
+ */
+static guint32 nm_device_wireless_discover_capabilities (NMDevice *dev)
+{
+ NMSock * sk;
+ int err;
+ wireless_scan_head scan_data;
+ guint32 caps = NM_DEVICE_CAP_NONE;
+
+ g_return_val_if_fail (dev != NULL, NM_DEVICE_CAP_NONE);
+ g_return_val_if_fail (nm_device_is_wireless (dev), NM_DEVICE_CAP_NONE);
+
+ /* A test wireless device can always scan (we generate fake scan data for it) */
+ if (dev->test_device)
+ caps |= NM_DEVICE_CAP_WIRELESS_SCAN;
+ else
+ {
+ if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL)))
+ {
+ err = iw_scan (nm_dev_sock_get_fd (sk), (char *)nm_device_get_iface (dev), WIRELESS_EXT, &scan_data);
+ nm_dispose_scan_results (scan_data.result);
+ if (!((err == -1) && (errno == EOPNOTSUPP)))
+ caps |= NM_DEVICE_CAP_WIRELESS_SCAN;
+ nm_dev_sock_close (sk);
+ }
+ }
+
+ return caps;
+}
+
+
+/*
+ * nm_device_wireless_discover_capabilities
+ *
+ * Figure out wireless-specific capabilities
+ *
+ */
+static guint32 nm_device_wired_discover_capabilities (NMDevice *dev)
+{
+ guint32 caps = NM_DEVICE_CAP_NONE;
+ const char * udi = NULL;
+ char * usb_test = NULL;
+ LibHalContext *ctx = NULL;
+
+ g_return_val_if_fail (dev != NULL, NM_DEVICE_CAP_NONE);
+ g_return_val_if_fail (nm_device_is_wired (dev), NM_DEVICE_CAP_NONE);
+ g_return_val_if_fail (dev->app_data != NULL, NM_DEVICE_CAP_NONE);
+
+ /* cipsec devices are also explicitly unsupported at this time */
+ if (strstr (nm_device_get_iface (dev), "cipsec"))
+ return NM_DEVICE_CAP_NONE;
+
+ /* Ignore Ethernet-over-USB devices too for the moment (Red Hat #135722) */
+ ctx = dev->app_data->hal_ctx;
+ udi = nm_device_get_udi (dev);
+ if ( libhal_device_property_exists (ctx, udi, "usb.interface.class", NULL)
+ && (usb_test = libhal_device_get_property_string (ctx, udi, "usb.interface.class", NULL)))
+ {
+ libhal_free_string (usb_test);
+ return NM_DEVICE_CAP_NONE;
+ }
+
+ if (supports_ethtool_carrier_detect (dev) || supports_mii_carrier_detect (dev))
+ caps |= NM_DEVICE_CAP_CARRIER_DETECT;
+
+ return caps;
+}
+
+
+/*
+ * nm_device_discover_capabilities
+ *
+ * Called only at device initialization time to discover device-specific
+ * capabilities.
+ *
+ */
+static guint32 nm_device_discover_capabilities (NMDevice *dev)
+{
+ guint32 caps = NM_DEVICE_CAP_NONE;
+
+ g_return_val_if_fail (dev != NULL, NM_DEVICE_CAP_NONE);
+
+ /* Don't touch devices that we already don't support */
+ if (!(dev->capabilities & NM_DEVICE_CAP_NM_SUPPORTED))
+ return NM_DEVICE_CAP_NONE;
+
+ if (nm_device_is_wired (dev))
+ caps |= nm_device_wired_discover_capabilities (dev);
+ else if (nm_device_is_wireless (dev))
+ caps |= nm_device_wireless_discover_capabilities (dev);
+
+ return caps;
+}
+
+
+/*
* nm_device_get_app_data
*
*/
@@ -621,6 +769,17 @@ const char * nm_device_get_iface (NMDevice *dev)
/*
+ * Get/set functions for driver
+ */
+const char * nm_device_get_driver (NMDevice *dev)
+{
+ g_return_val_if_fail (dev != NULL, NULL);
+
+ return (dev->driver);
+}
+
+
+/*
* Get/set functions for type
*/
guint nm_device_get_type (NMDevice *dev)
@@ -646,13 +805,13 @@ gboolean nm_device_is_wired (NMDevice *dev)
/*
- * Accessor for driver support level
+ * Accessor for device capabilities
*/
-NMDriverSupportLevel nm_device_get_driver_support_level (NMDevice *dev)
+guint32 nm_device_get_capabilities (NMDevice *dev)
{
- g_return_val_if_fail (dev != NULL, NM_DRIVER_UNSUPPORTED);
+ g_return_val_if_fail (dev != NULL, NM_DEVICE_CAP_NONE);
- return (dev->driver_support_level);
+ return dev->capabilities;
}
@@ -695,7 +854,7 @@ void nm_device_set_link_active (NMDevice *dev, const gboolean link_active)
* must manually choose semi-supported devices.
*
*/
- if (nm_device_is_wired (dev) && (nm_device_get_driver_support_level (dev) == NM_DRIVER_FULLY_SUPPORTED))
+ if (nm_device_is_wired (dev) && (nm_device_get_capabilities (dev) & NM_DEVICE_CAP_CARRIER_DETECT))
{
gboolean do_switch = act_dev ? FALSE : TRUE; /* If no currently active device, switch to this one */
NMActRequest * act_req;
@@ -726,7 +885,7 @@ gboolean nm_device_get_supports_wireless_scan (NMDevice *dev)
if (!nm_device_is_wireless (dev))
return (FALSE);
- return (dev->options.wireless.supports_wireless_scan);
+ return (dev->capabilities & NM_DEVICE_CAP_WIRELESS_SCAN);
}
@@ -740,7 +899,7 @@ gboolean nm_device_get_supports_carrier_detect (NMDevice *dev)
if (!nm_device_is_wired (dev))
return (FALSE);
- return (dev->options.wired.has_carrier_detect);
+ return (dev->capabilities & NM_DEVICE_CAP_CARRIER_DETECT);
}
/*
@@ -866,7 +1025,7 @@ static gboolean nm_device_probe_wired_link_state (NMDevice *dev)
* they never get auto-selected by NM. User has to force them on us,
* so we just hope the user knows whether or not the cable's plugged in.
*/
- if (dev->options.wired.has_carrier_detect != TRUE)
+ if (!(dev->capabilities & NM_DEVICE_CAP_CARRIER_DETECT))
link = TRUE;
return link;
@@ -1850,9 +2009,6 @@ gboolean nm_device_activation_start (NMActRequest *req)
g_return_val_if_fail (!nm_device_is_activating (dev), TRUE); /* Return if activation has already begun */
- if (nm_device_get_driver_support_level (dev) == NM_DRIVER_UNSUPPORTED)
- return FALSE;
-
nm_act_request_ref (req);
dev->act_request = req;
dev->quit_activation = FALSE;
@@ -3212,7 +3368,7 @@ gboolean nm_device_deactivate (NMDevice *dev)
nm_device_deactivate_quickly (dev);
- if (nm_device_get_driver_support_level (dev) == NM_DRIVER_UNSUPPORTED)
+ if (!(nm_device_get_capabilities (dev) & NM_DEVICE_CAP_NM_SUPPORTED))
return TRUE;
/* Remove any device nameservers and domains */
@@ -3971,9 +4127,10 @@ static gboolean nm_completion_scan_has_results (int tries, nm_completion_args ar
*/
static gboolean nm_device_wireless_scan (gpointer user_data)
{
- NMWirelessScanCB *scan_cb = (NMWirelessScanCB *)(user_data);
- NMDevice *dev = NULL;
- NMWirelessScanResults *scan_results = NULL;
+ NMWirelessScanCB * scan_cb = (NMWirelessScanCB *)(user_data);
+ NMDevice * dev = NULL;
+ NMWirelessScanResults * scan_results = NULL;
+ guint32 caps;
g_return_val_if_fail (scan_cb != NULL, FALSE);
@@ -3984,6 +4141,13 @@ static gboolean nm_device_wireless_scan (gpointer user_data)
return FALSE;
}
+ caps = nm_device_get_capabilities (dev);
+ if (!(caps & NM_DEVICE_CAP_NM_SUPPORTED) || !(caps & NM_DEVICE_CAP_WIRELESS_SCAN))
+ {
+ g_free (scan_cb);
+ return FALSE;
+ }
+
/* Reschedule ourselves if all wireless is disabled, we're asleep,
* or we are currently activating.
*/