wifi: add on-demand WiFi scan support
authorGary Ching-Pang Lin <chingpang@gmail.com>
Tue, 5 Jun 2012 03:19:41 +0000 (11:19 +0800)
committerDan Williams <dcbw@redhat.com>
Thu, 7 Jun 2012 20:06:48 +0000 (15:06 -0500)
A new D-Bus method was added to invoke the on-demand WiFi scan.

TODO
introspection/nm-device-wifi.xml
src/nm-device-wifi.c

diff --git a/TODO b/TODO
index 6ce69d8..f08da71 100644 (file)
--- a/TODO
+++ b/TODO
@@ -53,44 +53,6 @@ provide Ad-Hoc connection sharing support for those devices and switch between
 Ad-Hoc and AP mode depending on device capabilities.
 
 
-* On-Demand WiFi Scan support
-
-Single-user and embedded devices often use a continuous wifi scan when the
-networking configuration interface is open to quickly allow users to find their
-wifi network.  NM periodically scans, but this could take as long as 2 mintues
-to update the list.  Note that WiFi scans require 2 - 10 seconds to complete,
-and during this time normal traffic (video, VOIP, streaming music, downloads,
-etc) is not transmitted, so a WiFi scan is a disruptive operation to the user.
-
-A D-Bus method should be added to the NMDeviceWifi device to allow user
-applications to request a scan.  This request should be rate-limited to no
-more than once every 10 seconds to give time for traffic to resume when the
-scan is done, and to lessen the effect of any DDoS by malicious user
-applications.  This request should also be restricted by one or more PolicyKit
-permissions like org.freedesktop.NetworkManager.network-control.
-
-To begin, a new method definition should be added to the
-introspection/nm-device-wifi.xml for a method called "RequestScan" which takes
-an argument called "options" of type of "a{sv}".  This argument will be used
-later.  An annotation (like the other functions have) should be added so that
-the method will be called "impl_device_request_scan".
-
-Next, the corresponding method implementation should be added to
-src/nm-device-wifi.c by adding the prototype for impl_device_request_scan
-near the top of the file, and implementing it below.  The implementation will
-recieve a GHashTable corresponding to the "a{sv}" argument list from the XML
-file, but we can ignore that for now.
-
-The incoming request should be authenticated using nm_auth_get_caller_uid()
-and additionally starting a PolicyKit authentication check with
-with nm_auth_chain_new().  See the function manager_device_disconnect_request()
-in src/nm-manager.c for an example of this.
-
-Only after the caller is authorized to scan should the request be checked
-against the last scan timestamp, and if the last scan was 10 seconds or more
-ago, a new scan should be requested.
-
-
 * Reconnect to WiFi Networks Only If They Succeeded Once
 
 Currently, NetworkManager will attempt to connect to a previously attempted
index fb50762..531fc89 100644 (file)
       </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.
index 55ecfdb..15d4732 100644 (file)
@@ -56,6 +56,7 @@
 #include "nm-setting-ip4-config.h"
 #include "nm-setting-ip6-config.h"
 #include "nm-system.h"
+#include "nm-manager-auth.h"
 #include "nm-settings-connection.h"
 #include "nm-enum-types.h"
 #include "wifi-utils.h"
@@ -64,6 +65,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 +155,8 @@ struct _NMDeviceWifiPrivate {
        guint             periodic_source_id;
        guint             link_timeout_id;
 
+       glong             request_scan_time;
+
        NMDeviceWifiCapabilities capabilities;
 };
 
@@ -191,6 +198,8 @@ static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface * iface,
 
 static void schedule_scanlist_cull (NMDeviceWifi *self);
 
+static gboolean request_wireless_scan (gpointer user_data);
+
 /*****************************************************************/
 
 #define NM_WIFI_ERROR (nm_wifi_error_quark ())
@@ -330,6 +339,8 @@ constructor (GType type,
        }
        priv->ipw_rfkill_state = nm_device_wifi_get_ipw_rfkill_state (self);
 
+       priv->request_scan_time = 0;
+
        return object;
 }
 
@@ -1441,6 +1452,55 @@ impl_device_get_access_points (NMDeviceWifi *self,
        return TRUE;
 }
 
+static void
+request_scan_cb (NMDevice *device,
+                 DBusGMethodInvocation *context,
+                 GError *error,
+                 gpointer user_data)
+{
+       NMDeviceWifi *self = NM_DEVICE_WIFI (device);
+       NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+       GTimeVal now;
+
+       if (error) {
+               dbus_g_method_return_error (context, error);
+               g_clear_error (&error);
+       } else {
+               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);
+       }
+}
+
+static void
+impl_device_request_scan (NMDeviceWifi *self,
+                          GHashTable *options,
+                          DBusGMethodInvocation *context)
+{
+       NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+       GTimeVal now;
+
+       g_get_current_time (&now);
+       if (!priv->enabled || now.tv_sec - priv->request_scan_time < 10) {
+               dbus_g_method_return (context);
+               return;
+       }
+
+       /* Ask the manager to authenticate this request for us */
+       g_signal_emit_by_name (NM_DEVICE (self),
+                              NM_DEVICE_AUTH_REQUEST,
+                              context,
+                              NM_AUTH_PERMISSION_NETWORK_CONTROL,
+                              TRUE,
+                              request_scan_cb,
+                              NULL);
+
+       return;
+}
+
 static gboolean
 scanning_allowed (NMDeviceWifi *self)
 {