nm-device-wifi-p2p.c 13.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
17
 * Copyright 2018 - 2019 Red Hat, Inc.
18 19 20 21
 */

#include "nm-default.h"

22
#include "nm-device-wifi-p2p.h"
23 24

#include "nm-setting-connection.h"
25
#include "nm-setting-wifi-p2p.h"
26
#include "nm-utils.h"
27
#include "nm-wifi-p2p-peer.h"
28 29 30 31
#include "nm-object-private.h"
#include "nm-core-internal.h"
#include "nm-dbus-helpers.h"

32
#include "introspection/org.freedesktop.NetworkManager.Device.WifiP2P.h"
33

34
/*****************************************************************************/
35 36

typedef struct {
37
	NMDeviceWifiP2P *device;
38 39 40
	GSimpleAsyncResult *simple;
} RequestScanInfo;

41 42 43 44 45 46 47 48 49 50 51 52 53 54
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
	PROP_HW_ADDRESS,
	PROP_PEERS,
);

enum {
	PEER_ADDED,
	PEER_REMOVED,

	LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

55
typedef struct {
56
	NMDBusDeviceWifiP2P *proxy;
57 58 59 60

	char *hw_address;

	GPtrArray   *peers;
61
} NMDeviceWifiP2PPrivate;
62

63
/**
64
 * NMDeviceWifiP2P:
65 66 67
 *
 * Since: 1.16
 */
68
struct _NMDeviceWifiP2P {
69
	NMDevice parent;
70
	NMDeviceWifiP2PPrivate _priv;
71
};
72

73
struct _NMDeviceWifiP2PClass {
74
	NMDeviceClass parent;
75 76
};

77
G_DEFINE_TYPE (NMDeviceWifiP2P, nm_device_wifi_p2p, NM_TYPE_DEVICE)
78

79
#define NM_DEVICE_WIFI_P2P_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceWifiP2P, NM_IS_DEVICE_WIFI_P2P, NMDevice, NMObject)
80 81 82

/*****************************************************************************/

83
/**
84 85
 * nm_device_wifi_p2p_get_hw_address:
 * @device: a #NMDeviceWifiP2P
86
 *
87
 * Gets the actual hardware (MAC) address of the #NMDeviceWifiP2P
88 89 90 91 92 93 94
 *
 * Returns: the actual hardware address. This is the internal string used by the
 * device, and must not be modified.
 *
 * Since: 1.16
 **/
const char *
95
nm_device_wifi_p2p_get_hw_address (NMDeviceWifiP2P *device)
96
{
97
	g_return_val_if_fail (NM_IS_DEVICE_WIFI_P2P (device), NULL);
98

99
	return nm_str_not_empty (NM_DEVICE_WIFI_P2P_GET_PRIVATE (device)->hw_address);
100 101 102
}

/**
103 104
 * nm_device_wifi_p2p_get_peers:
 * @device: a #NMDeviceWifiP2P
105
 *
106
 * Gets all the found peers of the #NMDeviceWifiP2P.
107
 *
108 109
 * Returns: (element-type NMWifiP2PPeer): a #GPtrArray containing all the
 *          found #NMWifiP2PPeers.
110 111 112 113 114
 * The returned array is owned by the client and should not be modified.
 *
 * Since: 1.16
 **/
const GPtrArray *
115
nm_device_wifi_p2p_get_peers (NMDeviceWifiP2P *device)
116
{
117
	g_return_val_if_fail (NM_IS_DEVICE_WIFI_P2P (device), NULL);
118

119
	return NM_DEVICE_WIFI_P2P_GET_PRIVATE (device)->peers;
120 121 122
}

/**
123 124
 * nm_device_wifi_p2p_get_peer_by_path:
 * @device: a #NMDeviceWifiP2P
125 126
 * @path: the object path of the peer
 *
127
 * Gets a #NMWifiP2PPeer by path.
128 129 130 131 132
 *
 * Returns: (transfer none): the peer or %NULL if none is found.
 *
 * Since: 1.16
 **/
133 134
NMWifiP2PPeer *
nm_device_wifi_p2p_get_peer_by_path (NMDeviceWifiP2P *device,
135 136 137 138
                                     const char *path)
{
	const GPtrArray *peers;
	int i;
139
	NMWifiP2PPeer *peer = NULL;
140

141
	g_return_val_if_fail (NM_IS_DEVICE_WIFI_P2P (device), NULL);
142 143
	g_return_val_if_fail (path != NULL, NULL);

144
	peers = nm_device_wifi_p2p_get_peers (device);
145 146 147 148
	if (!peers)
		return NULL;

	for (i = 0; i < peers->len; i++) {
149
		NMWifiP2PPeer *candidate = g_ptr_array_index (peers, i);
150 151 152 153 154 155 156 157 158
		if (!strcmp (nm_object_get_path (NM_OBJECT (candidate)), path)) {
			peer = candidate;
			break;
		}
	}

	return peer;
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
static void
start_find_finished_cb (GObject      *obj,
                        GAsyncResult *res,
                        gpointer user_data)
{
	NMDBusDeviceWifiP2P *proxy = (NMDBusDeviceWifiP2P*) obj;
	gs_unref_object GTask *task = G_TASK (user_data);
	GError *error = NULL;
	gboolean success;

	success = nmdbus_device_wifi_p2p_call_start_find_finish (proxy, res, &error);
	if (!success)
		g_task_return_error (task, error);
	else
		g_task_return_boolean (task, TRUE);
}

/**
 * nm_device_wifi_p2p_start_find:
 * @device: a #NMDeviceWifiP2P
 * @options: (allow-none): optional options passed to StartFind.
 * @cancellable: a #GCancellable, or %NULL
 * @callback: a #GAsyncReadyCallback, or %NULL
 * @user_data: user_data for @callback
 *
 * Request NM to search for Wi-Fi P2P peers on @device. Note that the call
 * returns immediately after requesting the find, and it may take some time
 * after that for peers to be found.
 *
 * The find operation will run for 30s by default. You can stop it earlier
 * using nm_device_p2p_wifi_stop_find().
 *
 * Since: 1.16
 **/
void
nm_device_wifi_p2p_start_find (NMDeviceWifiP2P     *device,
                               GVariant            *options,
                               GCancellable        *cancellable,
                               GAsyncReadyCallback  callback,
                               gpointer             user_data)
{
	NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (device);
	GTask *task;

	g_return_if_fail (NM_IS_DEVICE_WIFI_P2P (device));

	task = g_task_new (device, cancellable, callback, user_data);

	if (!options)
		options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
	nmdbus_device_wifi_p2p_call_start_find (priv->proxy,
	                                        options,
	                                        cancellable,
	                                        start_find_finished_cb,
	                                        task);
}

/**
 * nm_device_wifi_p2p_start_find_finish:
 * @device: a #NMDeviceWifiP2P
 * @result: the #GAsyncResult
 * @error: #GError return address
 *
 * Finish an operation started by nm_device_wifi_p2p_start_find().
 *
 * Returns: %TRUE if the call was successful
 *
 * Since: 1.16
 **/
gboolean
nm_device_wifi_p2p_start_find_finish (NMDeviceWifiP2P  *device,
                                      GAsyncResult     *result,
                                      GError          **error)
{
	return g_task_propagate_boolean (G_TASK (result), error);
}

static void
stop_find_finished_cb (GObject      *obj,
                       GAsyncResult *res,
                       gpointer user_data)
{
	NMDBusDeviceWifiP2P *proxy = (NMDBusDeviceWifiP2P*) obj;
	gs_unref_object GTask *task = G_TASK (user_data);
	GError *error = NULL;
	gboolean success;

	success = nmdbus_device_wifi_p2p_call_stop_find_finish (proxy, res, &error);
	if (!success)
		g_task_return_error (task, error);
	else
		g_task_return_boolean (task, TRUE);
}

/**
 * nm_device_wifi_p2p_stop_find:
 * @device: a #NMDeviceWifiP2P
 * @cancellable: a #GCancellable, or %NULL
 * @callback: a #GAsyncReadyCallback, or %NULL
 * @user_data: user_data for @callback
 *
 * Request NM to stop any ongoing find operation for Wi-Fi P2P peers on @device.
 *
 * Since: 1.16
 **/
void
nm_device_wifi_p2p_stop_find (NMDeviceWifiP2P     *device,
                              GCancellable        *cancellable,
                              GAsyncReadyCallback  callback,
                              gpointer             user_data)
{
	NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (device);
	GTask *task;

	g_return_if_fail (NM_IS_DEVICE_WIFI_P2P (device));

	task = g_task_new (device, cancellable, callback, user_data);

	nmdbus_device_wifi_p2p_call_stop_find (priv->proxy,
	                                       cancellable,
	                                       stop_find_finished_cb,
	                                       task);
}

/**
 * nm_device_wifi_p2p_stop_find_finish:
 * @device: a #NMDeviceWifiP2P
 * @result: the #GAsyncResult
 * @error: #GError return address
 *
 * Finish an operation started by nm_device_wifi_p2p_stop_find().
 *
 * Returns: %TRUE if the call was successful
 *
 * Since: 1.16
 **/
gboolean
nm_device_wifi_p2p_stop_find_finish (NMDeviceWifiP2P  *device,
                                      GAsyncResult     *result,
                                      GError          **error)
{
	return g_task_propagate_boolean (G_TASK (result), error);
}

303
static void
304
clean_up_peers (NMDeviceWifiP2P *self)
305
{
306
	NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self);
307

308
	while (priv->peers->len > 0) {
309
		NMWifiP2PPeer *peer;
310

311 312
		peer = priv->peers->pdata[priv->peers->len - 1];
		g_ptr_array_remove_index (priv->peers, priv->peers->len - 1);
313

314
		g_signal_emit (self, signals[PEER_REMOVED], 0, peer);
315 316 317 318 319 320
	}
}

static gboolean
connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
{
321
	if (!NM_DEVICE_CLASS (nm_device_wifi_p2p_parent_class)->connection_compatible (device, connection, error))
322 323
		return FALSE;

324
	if (!nm_connection_is_type (connection, NM_SETTING_WIFI_P2P_SETTING_NAME)) {
325
		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
326
		                     _("The connection was not a Wi-Fi P2P connection."));
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
		return FALSE;
	}

	return TRUE;
}

static GType
get_setting_type (NMDevice *device)
{
	return NM_TYPE_SETTING_WIRELESS;
}

static const char *
get_hw_address (NMDevice *device)
{
342
	return nm_device_wifi_p2p_get_hw_address (NM_DEVICE_WIFI_P2P (device));
343 344
}

345 346 347 348 349 350
static const char *
get_type_description (NMDevice *device)
{
	return "wifi-p2p";
}

351 352 353 354 355 356 357 358
/*****************************************************************************/

static void
get_property (GObject *object,
              guint prop_id,
              GValue *value,
              GParamSpec *pspec)
{
359
	NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (object);
360 361 362

	switch (prop_id) {
	case PROP_HW_ADDRESS:
363
		g_value_set_string (value, nm_device_wifi_p2p_get_hw_address (self));
364 365
		break;
	case PROP_PEERS:
366
		g_value_take_boxed (value, _nm_utils_copy_object_array (nm_device_wifi_p2p_get_peers (self)));
367 368 369 370 371 372 373 374
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}

static void
375
nm_device_wifi_p2p_init (NMDeviceWifiP2P *device)
376
{
377
	NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (device);
378 379 380 381 382 383 384

	priv->peers = g_ptr_array_new ();
}

static void
init_dbus (NMObject *object)
{
385
	NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (object);
386
	const NMPropertiesInfo property_info[] = {
387 388
		{ NM_DEVICE_WIFI_P2P_HW_ADDRESS,           &priv->hw_address },
		{ NM_DEVICE_WIFI_P2P_PEERS,                &priv->peers, NULL, NM_TYPE_WIFI_P2P_PEER, "peer" },
389 390 391
		{ NULL },
	};

392
	NM_OBJECT_CLASS (nm_device_wifi_p2p_parent_class)->init_dbus (object);
393

394
	priv->proxy = NMDBUS_DEVICE_WIFI_P2P (_nm_object_get_proxy (object, NM_DBUS_INTERFACE_DEVICE_WIFI_P2P));
395
	_nm_object_register_properties (object,
396
	                                NM_DBUS_INTERFACE_DEVICE_WIFI_P2P,
397 398 399 400 401 402
	                                property_info);
}

static void
dispose (GObject *object)
{
403
	clean_up_peers (NM_DEVICE_WIFI_P2P (object));
404

405
	G_OBJECT_CLASS (nm_device_wifi_p2p_parent_class)->dispose (object);
406 407 408 409 410
}

static void
finalize (GObject *object)
{
411
	NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (object);
412

413
	g_clear_object (&priv->proxy);
414
	g_free (priv->hw_address);
415 416
	if (priv->peers)
		g_ptr_array_unref (priv->peers);
417

418
	G_OBJECT_CLASS (nm_device_wifi_p2p_parent_class)->finalize (object);
419 420 421
}

static void
422
nm_device_wifi_p2p_class_init (NMDeviceWifiP2PClass *wifi_class)
423 424 425 426 427 428
{
	GObjectClass *object_class = G_OBJECT_CLASS (wifi_class);
	NMObjectClass *nm_object_class = NM_OBJECT_CLASS (wifi_class);
	NMDeviceClass *device_class = NM_DEVICE_CLASS (wifi_class);

	object_class->get_property = get_property;
429 430
	object_class->dispose      = dispose;
	object_class->finalize     = finalize;
431 432

	device_class->connection_compatible = connection_compatible;
433 434
	device_class->get_setting_type      = get_setting_type;
	device_class->get_hw_address        = get_hw_address;
435
	device_class->get_type_description  = get_type_description;
436

437
	nm_object_class->init_dbus = init_dbus;
438 439

	/**
440
	 * NMDeviceWifiP2P:hw-address:
441 442 443 444 445
	 *
	 * The hardware (MAC) address of the device.
	 *
	 * Since: 1.16
	 **/
446
	obj_properties[PROP_HW_ADDRESS] =
447
	    g_param_spec_string (NM_DEVICE_WIFI_P2P_HW_ADDRESS, "", "",
448 449 450
	                         NULL,
	                         G_PARAM_READABLE |
	                         G_PARAM_STATIC_STRINGS);
451 452

	/**
453
	 * NMDeviceWifiP2P:peers: (type GPtrArray(NMWifiP2PPeer))
454
	 *
455
	 * List of all Wi-Fi P2P peers the device can see.
456 457 458
	 *
	 * Since: 1.16
	 **/
459
	obj_properties[PROP_PEERS] =
460
	    g_param_spec_boxed (NM_DEVICE_WIFI_P2P_PEERS, "", "",
461 462 463
	                        G_TYPE_PTR_ARRAY,
	                        G_PARAM_READABLE |
	                        G_PARAM_STATIC_STRINGS);
464

465
	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
466 467

	/**
468 469
	 * NMDeviceWifiP2P::peer-added:
	 * @device: the Wi-Fi P2P device that received the signal
470 471
	 * @peer: the new access point
	 *
472
	 * Notifies that a #NMWifiP2PPeer is added to the Wi-Fi P2P device.
473 474 475 476
	 *
	 * Since: 1.16
	 **/
	signals[PEER_ADDED] =
477 478 479 480 481 482 483
	    g_signal_new ("peer-added",
	                 G_OBJECT_CLASS_TYPE (object_class),
	                 G_SIGNAL_RUN_FIRST,
	                 0, NULL, NULL,
	                 g_cclosure_marshal_VOID__OBJECT,
	                 G_TYPE_NONE, 1,
	                 G_TYPE_OBJECT);
484 485

	/**
486 487
	 * NMDeviceWifiP2P::peer-removed:
	 * @device: the Wi-Fi P2P device that received the signal
488 489
	 * @peer: the removed access point
	 *
490
	 * Notifies that a #NMWifiP2PPeer is removed from the Wi-Fi P2P device.
491 492 493 494
	 *
	 * Since: 1.16
	 **/
	signals[PEER_REMOVED] =
495 496 497 498 499 500 501
	    g_signal_new ("peer-removed",
	                 G_OBJECT_CLASS_TYPE (object_class),
	                 G_SIGNAL_RUN_FIRST,
	                 0, NULL, NULL,
	                 g_cclosure_marshal_VOID__OBJECT,
	                 G_TYPE_NONE, 1,
	                 G_TYPE_OBJECT);
502
}