Commit 32c34a8c authored by Jiří Klimeš's avatar Jiří Klimeš

merge: 'ssids' RequestScan() option, nmcli connecting hidden SSID (rh #752173)

Add 'ssids' option to RequestScan() DBus call allowing scanning multiple SSIDs,
support that in libnm and nmcli. And fix nmcli for connecting to hidden SSIDs.

https://bugzilla.gnome.org/show_bug.cgi?id=752173
parents b019052b 5955a66e
......@@ -264,8 +264,8 @@ usage (void)
" delete <ifname> ...\n\n"
" wifi [list [ifname <ifname>] [bssid <BSSID>]]\n\n"
" wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n"
" [bssid <BSSID>] [name <name>] [private yes|no]\n\n"
" wifi rescan [[ifname] <ifname>]\n\n"
" [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n\n"
" wifi rescan [ifname <ifname>] [[ssid <SSID to scan>] ...]\n\n"
));
}
......@@ -345,7 +345,7 @@ usage_device_wifi (void)
"used to list APs for a particular interface, or with a specific BSSID.\n"
"\n"
"ARGUMENTS := connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n"
" [bssid <BSSID>] [name <name>] [private yes|no]\n"
" [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n"
"\n"
"Connect to a Wi-Fi network specified by SSID or BSSID. The command creates\n"
"a new connection and then activates it on a device. This is a command-line\n"
......@@ -356,12 +356,14 @@ usage_device_wifi (void)
"only open, WEP and WPA-PSK networks are supported at the moment. It is also\n"
"assumed that IP configuration is obtained via DHCP.\n"
"\n"
"ARGUMENTS := rescan [[ifname] <ifname>]\n"
"ARGUMENTS := rescan [ifname <ifname>] [[ssid <SSID to scan>] ...]\n"
"\n"
"Request that NetworkManager immediately re-scan for available access points.\n"
"NetworkManager scans Wi-Fi networks periodically, but in some cases it might\n"
"be useful to start scanning manually. Note that this command does not show\n"
"the APs, use 'nmcli device wifi list' for that.\n\n"));
"be useful to start scanning manually. 'ssid' allows scanning for a specific\n"
"SSID, which is useful for APs with hidden SSIDs. More 'ssid' parameters can be\n"
"given. Note that this command does not show the APs,\n"
"use 'nmcli device wifi list' for that.\n\n"));
}
/* quit main loop */
......@@ -2228,9 +2230,9 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
{
NMDevice *device = NULL;
NMAccessPoint *ap = NULL;
NM80211ApFlags ap_flags;
NM80211ApSecurityFlags ap_wpa_flags;
NM80211ApSecurityFlags ap_rsn_flags;
NM80211ApFlags ap_flags = NM_802_11_AP_FLAGS_NONE;
NM80211ApSecurityFlags ap_wpa_flags = NM_802_11_AP_SEC_NONE;
NM80211ApSecurityFlags ap_rsn_flags = NM_802_11_AP_SEC_NONE;
NMConnection *connection = NULL;
NMSettingConnection *s_con;
NMSettingWireless *s_wifi;
......@@ -2242,6 +2244,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
const char *password = NULL;
const char *con_name = NULL;
gboolean private = FALSE;
gboolean hidden = FALSE;
gboolean wep_passphrase = FALSE;
GByteArray *bssid1_arr = NULL;
GByteArray *bssid2_arr = NULL;
......@@ -2341,6 +2344,19 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
g_clear_error (&err_tmp);
goto error;
}
} else if (strcmp (*argv, "hidden") == 0) {
GError *err_tmp = NULL;
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
if (!nmc_string_to_bool (*argv, &hidden, &err_tmp)) {
g_string_printf (nmc->return_text, _("Error: %s: %s."), *(argv-1), err_tmp->message);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
g_clear_error (&err_tmp);
goto error;
}
} else {
g_printerr (_("Unknown parameter: %s\n"), *argv);
}
......@@ -2377,14 +2393,41 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
goto error;
}
/* For hidden SSID first scan it so that NM learns about the AP */
if (hidden) {
GVariantBuilder builder, array_builder;
GVariant *options;
GError *scan_err = NULL;
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aay"));
g_variant_builder_add (&array_builder, "@ay",
g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, param_user, strlen (param_user), 1));
g_variant_builder_add (&builder, "{sv}", "ssids", g_variant_builder_end (&array_builder));
options = g_variant_builder_end (&builder);
nm_device_wifi_request_scan_options (NM_DEVICE_WIFI (device), options, NULL, &scan_err);
if (scan_err) {
g_string_printf (nmc->return_text, _("Error: Failed to scan hidden SSID: %s."),
scan_err->message);
g_clear_error (&scan_err);
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
goto error;
}
}
/* Find an AP to connect to */
ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user);
if (!ap && !ifname) {
/* AP not found. ifname was not specified, so try finding the AP on another device. */
while ((device = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) {
ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user);
if (ap)
NMDevice *dev;
/* AP not found, ifname was not specified, so try finding the AP on another device. */
while ((dev = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) {
ap = find_ap_on_device (dev, bssid1_arr, bssid1_arr ? NULL : param_user);
if (ap) {
device = dev;
break;
}
}
}
......@@ -2399,7 +2442,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
/* If there are some connection data from user, create a connection and
* fill them into proper settings. */
if (con_name || private || bssid2_arr || password)
if (con_name || private || bssid2_arr || password || hidden)
connection = nm_simple_connection_new ();
if (con_name || private) {
......@@ -2414,12 +2457,24 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
if (private)
nm_setting_connection_add_permission (s_con, "user", g_get_user_name (), NULL);
}
if (bssid2_arr) {
if (bssid2_arr || hidden) {
s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
nm_connection_add_setting (connection, NM_SETTING (s_wifi));
/* 'bssid' parameter is used to restrict the conenction only to the BSSID */
g_object_set (s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL);
/* 'bssid' parameter is used to restrict the connection only to the BSSID */
if (bssid2_arr)
g_object_set (s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL);
/* 'hidden' parameter is used to indicate that SSID is not broadcasted */
if (hidden) {
GBytes *ssid = g_bytes_new (param_user, strlen (param_user));
g_object_set (s_wifi,
NM_SETTING_WIRELESS_SSID, ssid,
NM_SETTING_WIRELESS_HIDDEN, hidden,
NULL);
g_bytes_unref (ssid);
}
}
/* handle password */
......@@ -2510,21 +2565,44 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
{
NMDevice *device;
const char *ifname = NULL;
GPtrArray *ssids;
const GPtrArray *devices;
int devices_idx;
GVariantBuilder builder, array_builder;
GVariant *options;
const char *ssid;
int i;
nmc->should_wait = TRUE;
ssids = g_ptr_array_new ();
/* Get the parameters */
if (argc > 0) {
while (argc > 0) {
if (strcmp (*argv, "ifname") == 0) {
if (ifname) {
g_string_printf (nmc->return_text, _("Error: '%s' cannot repeat."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
}
ifname = *argv;
ifname = *argv;
} else if (strcmp (*argv, "ssid") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
g_ptr_array_add (ssids, *argv);
} else
g_printerr (_("Unknown parameter: %s\n"), *argv);
argc--;
argv++;
}
/* Find Wi-Fi device to scan on. When no ifname is provided, the first Wi-Fi is used. */
......@@ -2541,12 +2619,31 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
goto error;
}
nm_device_wifi_request_scan_async (NM_DEVICE_WIFI (device), NULL,
request_rescan_cb, nmc);
if (ssids->len) {
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aay"));
for (i = 0; i < ssids->len; i++) {
ssid = g_ptr_array_index (ssids, i);
g_variant_builder_add (&array_builder, "@ay",
g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, ssid, strlen (ssid), 1));
}
g_variant_builder_add (&builder, "{sv}", "ssids", g_variant_builder_end (&array_builder));
options = g_variant_builder_end (&builder);
nm_device_wifi_request_scan_options_async (NM_DEVICE_WIFI (device), options,
NULL, request_rescan_cb, nmc);
} else
nm_device_wifi_request_scan_async (NM_DEVICE_WIFI (device),
NULL, request_rescan_cb, nmc);
g_ptr_array_free (ssids, FALSE);
return nmc->return_value;
error:
nmc->should_wait = FALSE;
g_ptr_array_free (ssids, FALSE);
return nmc->return_value;
}
......
......@@ -495,6 +495,7 @@ _nmcli_compl_ARGS()
stp| \
hairpin| \
save| \
hidden| \
private)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "yes no"
......@@ -579,7 +580,9 @@ _nmcli_compl_ARGS()
# remove the options already seen.
for i in ${!OPTIONS[*]}; do
if [[ "${OPTIONS[$i]}" = "${REMOVE_OPTIONS[0]}" || "${OPTIONS[$i]}" = "${REMOVE_OPTIONS[1]}" ]]; then
unset OPTIONS[$i]
if ! _nmcli_array_has_value OPTIONS_REPEATABLE "${OPTIONS[$i]}" ; then
unset OPTIONS[$i]
fi
fi
done
for i in ${!OPTIONS_MANDATORY[*]}; do
......@@ -737,7 +740,7 @@ _nmcli()
cur=''
fi
local OPTIONS_UNKNOWN_OPTION OPTIONS_TYPE OPTIONS_TYPED OPTIONS OPTIONS_MANDATORY COMMAND_ARGS_WAIT_OPTIONS OPTIONS_IP OPTIONS_MANDATORY OPTIONS_NEXT_GROUP OPTIONS_SEP
local OPTIONS_UNKNOWN_OPTION OPTIONS_TYPE OPTIONS_TYPED OPTIONS OPTIONS_MANDATORY COMMAND_ARGS_WAIT_OPTIONS OPTIONS_IP OPTIONS_MANDATORY OPTIONS_NEXT_GROUP OPTIONS_SEP OPTIONS_REPEATABLE
local COMMAND_CONNECTION_TYPE COMMAND_CONNECTION_ID OPTIONS_MANDATORY_IFNAME HELP_ONLY_AS_FIRST
local COMMAND_CONNECTION_ACTIVE=""
......@@ -1287,13 +1290,14 @@ _nmcli()
fi
else
_nmcli_array_delete_at words 0 3
local OPTIONS=(password wep-key-type ifname bssid name private)
local OPTIONS=(password wep-key-type ifname bssid name private hidden)
_nmcli_compl_ARGS
fi
;;
r|re|res|resc|resca|rescan)
_nmcli_array_delete_at words 0 2
OPTIONS=(ifname)
OPTIONS_REPEATABLE=(ssid)
OPTIONS=(ifname ssid)
_nmcli_compl_ARGS
;;
esac
......
......@@ -33,7 +33,8 @@
<method name="RequestScan">
<arg name="options" type="a{sv}" direction="in">
<tp:docstring>
Options of scan (currently unused argument).
Options of scan.
Currently 'ssids' option with value of "aay" type is supported.
</tp:docstring>
</arg>
<tp:docstring>
......
......@@ -851,6 +851,8 @@ global:
nm_access_point_get_last_seen;
nm_device_get_metered;
nm_device_get_nm_plugin_missing;
nm_device_wifi_request_scan_options;
nm_device_wifi_request_scan_options_async;
nm_metered_get_type;
nm_setting_802_1x_check_cert_scheme;
nm_setting_bridge_get_multicast_snooping;
......
......@@ -269,6 +269,52 @@ nm_device_wifi_get_access_point_by_path (NMDeviceWifi *device,
return ap;
}
static GVariant *
prepare_scan_options (GVariant *options)
{
GVariant *variant;
GVariantIter iter;
GVariantBuilder builder;
char *key;
GVariant *value;
if (!options)
variant = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
else {
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
g_variant_iter_init (&iter, options);
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
{
// FIXME: verify options here?
g_variant_builder_add (&builder, "{sv}", key, value);
}
variant = g_variant_builder_end (&builder);
}
return variant;
}
static gboolean
_device_wifi_request_scan (NMDeviceWifi *device,
GVariant *options,
GCancellable *cancellable,
GError **error)
{
gboolean ret;
GVariant *variant;
g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), FALSE);
variant = prepare_scan_options (options);
ret = nmdbus_device_wifi_call_request_scan_sync (NM_DEVICE_WIFI_GET_PRIVATE (device)->proxy,
variant,
cancellable, error);
if (error && *error)
g_dbus_error_strip_remote_error (*error);
return ret;
}
/**
* nm_device_wifi_request_scan:
* @device: a #NMDeviceWifi
......@@ -287,17 +333,36 @@ nm_device_wifi_request_scan (NMDeviceWifi *device,
GCancellable *cancellable,
GError **error)
{
gboolean ret;
g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), FALSE);
return _device_wifi_request_scan (device, NULL, cancellable, error);
}
ret = nmdbus_device_wifi_call_request_scan_sync (NM_DEVICE_WIFI_GET_PRIVATE (device)->proxy,
g_variant_new_array (G_VARIANT_TYPE ("{sv}"),
NULL, 0),
cancellable, error);
if (error && *error)
g_dbus_error_strip_remote_error (*error);
return ret;
/**
* nm_device_wifi_request_scan_options:
* @device: a #NMDeviceWifi
* @options: dictionary with options for RequestScan(), or %NULL
* @cancellable: a #GCancellable, or %NULL
* @error: location for a #GError, or %NULL
*
* Request NM to scan for access points on @device. Note that the function
* returns immediately after requesting the scan, and it may take some time
* after that for the scan to complete.
* This is the same as @nm_device_wifi_request_scan except it accepts @options
* for the scanning. The argument is the dictionary passed to RequestScan()
* D-Bus call. Valid otions inside the dictionary are:
* 'ssids' => array of SSIDs (saay)
*
* Returns: %TRUE on success, %FALSE on error, in which case @error will be
* set.
*
* Since: 1.2
**/
gboolean
nm_device_wifi_request_scan_options (NMDeviceWifi *device,
GVariant *options,
GCancellable *cancellable,
GError **error)
{
return _device_wifi_request_scan (device, options, cancellable, error);
}
static void
......@@ -324,19 +389,9 @@ request_scan_cb (GObject *source,
g_slice_free (RequestScanInfo, info);
}
/**
* nm_device_wifi_request_scan_async:
* @device: a #NMDeviceWifi
* @cancellable: a #GCancellable, or %NULL
* @callback: callback to be called when the scan has been requested
* @user_data: caller-specific data passed to @callback
*
* Request NM to scan for access points on @device. Note that @callback will be
* called immediately after requesting the scan, and it may take some time after
* that for the scan to complete.
**/
void
nm_device_wifi_request_scan_async (NMDeviceWifi *device,
static void
_device_wifi_request_scan_async (NMDeviceWifi *device,
GVariant *options,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
......@@ -344,6 +399,7 @@ nm_device_wifi_request_scan_async (NMDeviceWifi *device,
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
RequestScanInfo *info;
GSimpleAsyncResult *simple;
GVariant *variant;
g_return_if_fail (NM_IS_DEVICE_WIFI (device));
......@@ -362,12 +418,62 @@ nm_device_wifi_request_scan_async (NMDeviceWifi *device,
info->device = device;
info->simple = simple;
variant = prepare_scan_options (options);
priv->scan_info = info;
nmdbus_device_wifi_call_request_scan (NM_DEVICE_WIFI_GET_PRIVATE (device)->proxy,
g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0),
variant,
cancellable, request_scan_cb, info);
}
/**
* nm_device_wifi_request_scan_async:
* @device: a #NMDeviceWifi
* @cancellable: a #GCancellable, or %NULL
* @callback: callback to be called when the scan has been requested
* @user_data: caller-specific data passed to @callback
*
* Request NM to scan for access points on @device. Note that @callback will be
* called immediately after requesting the scan, and it may take some time after
* that for the scan to complete.
**/
void
nm_device_wifi_request_scan_async (NMDeviceWifi *device,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
_device_wifi_request_scan_async (device, NULL, cancellable, callback, user_data);
}
/**
* nm_device_wifi_request_scan_options_async:
* @device: a #NMDeviceWifi
* @options: dictionary with options for RequestScan(), or %NULL
* @cancellable: a #GCancellable, or %NULL
* @callback: callback to be called when the scan has been requested
* @user_data: caller-specific data passed to @callback
*
* Request NM to scan for access points on @device. Note that @callback will be
* called immediately after requesting the scan, and it may take some time after
* that for the scan to complete.
* This is the same as @nm_device_wifi_request_scan_async except it accepts @options
* for the scanning. The argument is the dictionary passed to RequestScan()
* D-Bus call. Valid otions inside the dictionary are:
* 'ssids' => array of SSIDs (saay)
*
* Since: 1.2
**/
void
nm_device_wifi_request_scan_options_async (NMDeviceWifi *device,
GVariant *options,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
_device_wifi_request_scan_async (device, options, cancellable, callback, user_data);
}
/**
* nm_device_wifi_request_scan_finish:
* @device: a #NMDeviceWifi
......
......@@ -77,11 +77,21 @@ const GPtrArray * nm_device_wifi_get_access_points (NMDeviceWifi *
gboolean nm_device_wifi_request_scan (NMDeviceWifi *device,
GCancellable *cancellable,
GError **error);
NM_AVAILABLE_IN_1_2
gboolean nm_device_wifi_request_scan_options (NMDeviceWifi *device,
GVariant *options,
GCancellable *cancellable,
GError **error);
void nm_device_wifi_request_scan_async (NMDeviceWifi *device,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
NM_AVAILABLE_IN_1_2
void nm_device_wifi_request_scan_options_async (NMDeviceWifi *device,
GVariant *options,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean nm_device_wifi_request_scan_finish (NMDeviceWifi *device,
GAsyncResult *result,
GError **error);
......
......@@ -21,7 +21,7 @@
.\"
.\" Copyright 2010 - 2015 Red Hat, Inc.
.\"
.TH NMCLI "1" "19 February 2015"
.TH NMCLI "1" "12 August 2015"
.SH NAME
nmcli \- command\(hyline tool for controlling NetworkManager
......@@ -802,7 +802,8 @@ List available Wi\(hyFi access points. The \fIifname\fP and \fIbssid\fP options
can be used to list APs for a particular interface or with a specific BSSID,
respectively.
.TP
.B wifi connect <(B)SSID> [password <password>] [wep\-key\-type key|phrase] [ifname <ifname>] [bssid <BSSID>] [name <name>] [private yes|no]
.B wifi connect <(B)SSID> [password <password>] [wep\-key\-type key|phrase] [ifname <ifname>] [bssid <BSSID>] [name <name>]
.B [private yes|no] [hidden yes|no]
.br
Connect to a Wi\(hyFi network specified by SSID or BSSID. The command creates a new
connection and then activates it on a device. This is a command\(hyline counterpart
......@@ -830,13 +831,20 @@ Available options are:
.IP \fIprivate\fP 13
\(en if set to \fByes\fP, the connection will only be visible to the user who created it.
Otherwise the connection is system\(hywide, which is the default.
.IP \fIhidden\fP 13
\(en set to \fByes\fP when connecting for the first time to an AP not broadcasting its SSID.
Otherwise the SSID would not be found and the connection attempt would fail.
.RE
.TP
.B wifi rescan [[ifname] <ifname>]
.B wifi rescan [ifname <ifname>] [[ssid <SSID>] ...]
.br
Request that \fINetworkManager\fP immediately re-scan for available access points.
NetworkManager scans Wi\(hyFi networks periodically, but in some cases it can be
useful to start scanning manually (e.g. after resuming the computer).
useful to start scanning manually (e.g. after resuming the computer). By using
\fIssid\fP, it is possible to scan for a specific SSID, which is useful for APs
with hidden SSIDs. You can provide multiple \fIssid\fP parameters in order to
scan more SSIDs.
.br
This command does not show the APs, use 'nmcli device wifi list' for that.
.TP
......
......@@ -49,6 +49,7 @@
#include "nm-enum-types.h"
#include "nm-wifi-enum-types.h"
#include "nm-connection-provider.h"
#include "nm-core-internal.h"
#include "nmdbus-device-wifi.h"
......@@ -160,7 +161,7 @@ static void supplicant_iface_notify_current_bss (NMSupplicantInterface *iface,
GParamSpec *pspec,
NMDeviceWifi *self);
static gboolean request_wireless_scan (gpointer user_data);
static void request_wireless_scan (NMDeviceWifi *self, GVariant *scan_options);
static void emit_ap_added_removed (NMDeviceWifi *self,
guint signum,
......@@ -534,7 +535,7 @@ deactivate (NMDevice *device)
/* Ensure we trigger a scan after deactivating a Hotspot */
if (old_mode == NM_802_11_MODE_AP) {
cancel_pending_scan (self);
request_wireless_scan (self);
request_wireless_scan (self, NULL);
}
}
......@@ -1051,6 +1052,7 @@ request_scan_cb (NMDevice *device,
gpointer user_data)
{
NMDeviceWifi *self = NM_DEVICE_WIFI (device);
gs_unref_variant GVariant *new_scan_options = user_data;
if (error) {
g_dbus_method_invocation_return_gerror (context, error);
......@@ -1066,7 +1068,7 @@ request_scan_cb (NMDevice *device,
}
cancel_pending_scan (self);
request_wireless_scan (self);
request_wireless_scan (self, new_scan_options);
g_dbus_method_invocation_return_value (context, NULL);
}
......@@ -1115,7 +1117,7 @@ impl_device_wifi_request_scan (NMDeviceWifi *self,
NM_AUTH_PERMISSION_NETWORK_CONTROL,
TRUE,
request_scan_cb,
NULL);
options ? g_variant_ref (options) : NULL);
}
static gboolean
......@@ -1276,23 +1278,58 @@ build_hidden_probe_list (NMDeviceWifi *self)
return ssids;
}
static gboolean
request_wireless_scan (gpointer user_data)
static GPtrArray *
ssids_options_to_ptrarray (GVariant *value)
{
GPtrArray *ssids = NULL;
GByteArray *ssid_array;
GVariant *v;
const guint8 *bytes;
gsize len;
int num_ssids, i;
num_ssids = g_variant_n_children (value);
if (num_ssids) {
ssids = g_ptr_array_new_full (num_ssids, (GDestroyNotify) g_byte_array_unref);
for (i = 0; i < num_ssids; i++) {
v = g_variant_get_child_value (value, i);
bytes = g_variant_get_fixed_array (v, &len, sizeof (guint8));
ssid_array = g_byte_array_new ();
g_byte_array_append (ssid_array, bytes, len);
g_ptr_array_add (ssids, ssid_array);
}
}
return ssids;
}
static void
request_wireless_scan (NMDeviceWifi *self, GVariant *scan_options)
{
NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
gboolean backoff = FALSE;
GPtrArray *ssids = NULL;
if (priv->requested_scan) {
/* There's already a scan in progress */
return FALSE;
return;
}
if (check_scanning_allowed (self)) {
_LOGD (LOGD_WIFI_SCAN, "scanning requested");
ssids = build_hidden_probe_list (self);
if (scan_options) {
GVariant *val = g_variant_lookup_value (scan_options, "ssids", NULL);
if (val) {
if (g_variant_is_of_type (val, G_VARIANT_TYPE ("aay")))
ssids = ssids_options_to_ptrarray (val);
else
_LOGD (LOGD_WIFI_SCAN, "ignoring invalid 'ssids' scan option");
g_variant_unref (val);
}
}
if (!ssids)
ssids = build_hidden_probe_list (self);
if (nm_logging_enabled (LOGL_DEBUG, LOGD_WIFI_SCAN)) {
if (ssids) {
......@@ -1327,9 +1364,14 @@ request_wireless_scan (gpointer user_data)
priv->pending_scan_id = 0;
schedule_scan (self, backoff);
return FALSE;
}
static gboolean
request_wireless_scan_periodic (gpointer user_data)
{
request_wireless_scan (user_data, NULL);
return FALSE;
}
/*
* schedule_scan
......@@ -1357,7 +1399,7 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff)
factor = 1;
priv->pending_scan_id = g_timeout_add_seconds (next_scan,