[PATCH] wifi: add the on-demand WiFi scan support



A new dbus method was added to request the wifi device to scan the
access points.
---
 introspection/nm-device-wifi.xml |   13 ++++
 src/nm-device-wifi.c             |  130 ++++++++++++++++++++++++++++++++++++++
 src/nm-device-wifi.h             |    1 +
 3 files changed, 144 insertions(+), 0 deletions(-)

diff --git a/introspection/nm-device-wifi.xml b/introspection/nm-device-wifi.xml
index fb50762..531fc89 100644
--- a/introspection/nm-device-wifi.xml
+++ b/introspection/nm-device-wifi.xml
@@ -14,6 +14,19 @@
       </tp:docstring>
     </method>
 
+    <method name="RequestScan">
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_device_request_scan"/>
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg name="options" type="a{sv}" direction="in">
+        <tp:docstring>
+          Options of scan
+        </tp:docstring>
+      </arg>
+      <tp:docstring>
+        Request the device to scan
+      </tp:docstring>
+    </method>
+
     <property name="HwAddress" type="s" access="read">
       <tp:docstring>
         The active hardware address of the device.
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index ad1cfe3..417969e 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -45,6 +45,7 @@
 #include "nm-marshal.h"
 #include "NetworkManagerUtils.h"
 #include "nm-activation-request.h"
+#include "nm-dbus-manager.h"
 #include "nm-supplicant-manager.h"
 #include "nm-supplicant-interface.h"
 #include "nm-supplicant-config.h"
@@ -57,6 +58,7 @@
 #include "nm-setting-ip6-config.h"
 #include "nm-system.h"
 #include "nm-settings-connection.h"
+#include "nm-manager-auth.h"
 #include "nm-enum-types.h"
 #include "wifi-utils.h"
 
@@ -64,6 +66,10 @@ static gboolean impl_device_get_access_points (NMDeviceWifi *device,
                                                GPtrArray **aps,
                                                GError **err);
 
+static void impl_device_request_scan (NMDeviceWifi *device,
+                                      GHashTable *options,
+                                      DBusGMethodInvocation *context);
+
 #include "nm-device-wifi-glue.h"
 
 
@@ -150,6 +156,10 @@ struct _NMDeviceWifiPrivate {
 	guint             periodic_source_id;
 	guint             link_timeout_id;
 
+	NMDBusManager *   dbus_mgr;
+	GSList *          auth_chains;
+	glong             request_scan_time;
+
 	NMDeviceWifiCapabilities capabilities;
 };
 
@@ -330,6 +340,12 @@ constructor (GType type,
 	}
 	priv->ipw_rfkill_state = nm_device_wifi_get_ipw_rfkill_state (self);
 
+	priv->dbus_mgr = nm_dbus_manager_get ();
+	g_assert (priv->dbus_mgr);
+
+	priv->auth_chains = NULL;
+	priv->request_scan_time = 0;
+
 	return object;
 }
 
@@ -1441,6 +1457,112 @@ impl_device_get_access_points (NMDeviceWifi *self,
 	return TRUE;
 }
 
+static GError *
+request_scan_check_error (GError *auth_error,
+                          NMAuthCallResult result)
+{
+	if (auth_error) {
+		nm_log_dbg (LOGD_WIFI, "request scan failed: %s", auth_error->message);
+		return g_error_new (NM_WIFI_ERROR,
+		                    NM_WIFI_ERROR_PERMISSION_DENIED,
+		                    "request scan failed: %s",
+		                    auth_error->message);
+	} else if (result != NM_AUTH_CALL_RESULT_YES) {
+		return g_error_new (NM_WIFI_ERROR,
+		                    NM_WIFI_ERROR_PERMISSION_DENIED,
+		                    "Not authorized to request scan");
+	}
+	return NULL;
+}
+
+static void
+do_request_scan (NMAuthChain *chain,
+                 GError *auth_error,
+                 DBusGMethodInvocation *context,
+                 gpointer user_data)
+
+{
+	NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	NMAuthCallResult result;
+	GError *error = NULL;
+	GTimeVal now;
+
+	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
+
+	result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL));
+	error = request_scan_check_error (auth_error, result);
+	if (!error) {
+		g_get_current_time (&now);
+		cancel_pending_scan (self);
+		request_wireless_scan (self);
+		priv->request_scan_time = now.tv_sec;
+
+		dbus_g_method_return (context);
+	} else {
+		dbus_g_method_return_error (context, error);
+	}
+
+	g_clear_error (&error);
+	nm_auth_chain_unref (chain);
+}
+
+static void
+impl_device_request_scan (NMDeviceWifi *self,
+                          GHashTable *options,
+                          DBusGMethodInvocation *context)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	gulong sender_uid = G_MAXULONG;
+	char *error_desc = NULL;
+	GError *error = NULL;
+	NMAuthChain *chain;
+	GTimeVal now;
+
+	if (!priv->enabled)
+		return;
+
+	g_get_current_time (&now);
+	if (now.tv_sec - priv->request_scan_time < 10) {
+		dbus_g_method_return (context);
+		return;
+	}
+
+	/* Need to check the caller's permissions and stuff before we can
+	 * start the scan.
+	 */
+	if (!nm_auth_get_caller_uid (context,
+		                     priv->dbus_mgr,
+	                             &sender_uid,
+	                             &error_desc)) {
+		error = g_error_new_literal (NM_WIFI_ERROR,
+		                             NM_WIFI_ERROR_PERMISSION_DENIED,
+		                             error_desc);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+		g_free (error_desc);
+		return;
+	}
+
+	/* Yay for root */
+	if (0 == sender_uid) {
+		cancel_pending_scan (self);
+		request_wireless_scan (self);
+		priv->request_scan_time = now.tv_sec;
+		dbus_g_method_return (context);
+		return;
+	}
+
+	/* Otherwise validate the user request */
+	chain = nm_auth_chain_new (context, NULL, do_request_scan, self);
+	g_assert (chain);
+	priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+
+	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
+
+	return;
+}
+
 static gboolean
 scanning_allowed (NMDeviceWifi *self)
 {
@@ -3399,6 +3521,14 @@ dispose (GObject *object)
 		priv->ipw_rfkill_id = 0;
 	}
 
+	g_slist_foreach (priv->auth_chains, (GFunc) nm_auth_chain_unref, NULL);
+	g_slist_free (priv->auth_chains);
+
+	if (priv->dbus_mgr) {
+		g_object_unref (priv->dbus_mgr);
+		priv->dbus_mgr = NULL;
+	}
+
 	G_OBJECT_CLASS (nm_device_wifi_parent_class)->dispose (object);
 }
 
diff --git a/src/nm-device-wifi.h b/src/nm-device-wifi.h
index 1e665fc..1541121 100644
--- a/src/nm-device-wifi.h
+++ b/src/nm-device-wifi.h
@@ -46,6 +46,7 @@ typedef enum {
 	NM_WIFI_ERROR_CONNECTION_INVALID,          /*< nick=ConnectionInvalid >*/
 	NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,     /*< nick=ConnectionIncompatible >*/
 	NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND,      /*< nick=AccessPointNotFound >*/
+	NM_WIFI_ERROR_PERMISSION_DENIED,           /*< nick=PermissionDenied >*/
 } NMWifiError;
 
 #define NM_DEVICE_WIFI_HW_ADDRESS          "hw-address"
-- 
1.7.7



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]