1169689Skan/*
2169689Skan * WPA Supplicant / dbus-based control interface
3169689Skan * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4169689Skan * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
5169689Skan * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6169689Skan *
7169689Skan * This software may be distributed under the terms of the BSD license.
8169689Skan * See README for more details.
9169689Skan */
10169689Skan
11169689Skan#include "includes.h"
12169689Skan
13169689Skan#include "common.h"
14169689Skan#include "common/ieee802_11_defs.h"
15169689Skan#include "wps/wps.h"
16169689Skan#include "ap/sta_info.h"
17169689Skan#include "../config.h"
18169689Skan#include "../wpa_supplicant_i.h"
19169689Skan#include "../bss.h"
20169689Skan#include "../wpas_glue.h"
21169689Skan#include "dbus_new_helpers.h"
22169689Skan#include "dbus_dict_helpers.h"
23169689Skan#include "dbus_new.h"
24169689Skan#include "dbus_new_handlers.h"
25169689Skan#include "dbus_common_i.h"
26169689Skan#include "dbus_new_handlers_p2p.h"
27169689Skan#include "p2p/p2p.h"
28169689Skan#include "../p2p_supplicant.h"
29169689Skan
30169689Skan#ifdef CONFIG_AP /* until needed by something else */
31169689Skan
32169689Skan/*
33169689Skan * NameOwnerChanged handling
34169689Skan *
35169689Skan * Some services we provide allow an application to register for
36169689Skan * a signal that it needs. While it can also unregister, we must
37169689Skan * be prepared for the case where the application simply crashes
38169689Skan * and thus doesn't clean up properly. The way to handle this in
39169689Skan * DBus is to register for the NameOwnerChanged signal which will
40169689Skan * signal an owner change to NULL if the peer closes the socket
41169689Skan * for whatever reason.
42169689Skan *
43169689Skan * Handle this signal via a filter function whenever necessary.
44169689Skan * The code below also handles refcounting in case in the future
45169689Skan * there will be multiple instances of this subscription scheme.
46169689Skan */
47169689Skanstatic const char wpas_dbus_noc_filter_str[] =
48169689Skan	"interface=org.freedesktop.DBus,member=NameOwnerChanged";
49169689Skan
50169689Skan
51169689Skanstatic DBusHandlerResult noc_filter(DBusConnection *conn,
52169689Skan				    DBusMessage *message, void *data)
53169689Skan{
54169689Skan	struct wpas_dbus_priv *priv = data;
55169689Skan
56169689Skan	if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
57169689Skan		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
58169689Skan
59169689Skan	if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
60169689Skan				   "NameOwnerChanged")) {
61169689Skan		const char *name;
62169689Skan		const char *prev_owner;
63169689Skan		const char *new_owner;
64169689Skan		DBusError derr;
65169689Skan		struct wpa_supplicant *wpa_s;
66169689Skan
67169689Skan		dbus_error_init(&derr);
68169689Skan
69169689Skan		if (!dbus_message_get_args(message, &derr,
70169689Skan					   DBUS_TYPE_STRING, &name,
71169689Skan					   DBUS_TYPE_STRING, &prev_owner,
72169689Skan					   DBUS_TYPE_STRING, &new_owner,
73169689Skan					   DBUS_TYPE_INVALID)) {
74169689Skan			/* Ignore this error */
75			dbus_error_free(&derr);
76			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
77		}
78
79		for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
80			if (wpa_s->preq_notify_peer != NULL &&
81			    os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
82			    (new_owner == NULL || os_strlen(new_owner) == 0)) {
83				/* probe request owner disconnected */
84				os_free(wpa_s->preq_notify_peer);
85				wpa_s->preq_notify_peer = NULL;
86				wpas_dbus_unsubscribe_noc(priv);
87			}
88		}
89	}
90
91	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
92}
93
94
95void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv)
96{
97	priv->dbus_noc_refcnt++;
98	if (priv->dbus_noc_refcnt > 1)
99		return;
100
101	if (!dbus_connection_add_filter(priv->con, noc_filter, priv, NULL)) {
102		wpa_printf(MSG_ERROR, "dbus: failed to add filter");
103		return;
104	}
105
106	dbus_bus_add_match(priv->con, wpas_dbus_noc_filter_str, NULL);
107}
108
109
110void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv)
111{
112	priv->dbus_noc_refcnt--;
113	if (priv->dbus_noc_refcnt > 0)
114		return;
115
116	dbus_bus_remove_match(priv->con, wpas_dbus_noc_filter_str, NULL);
117	dbus_connection_remove_filter(priv->con, noc_filter, priv);
118}
119
120#endif /* CONFIG_AP */
121
122
123/**
124 * wpas_dbus_signal_interface - Send a interface related event signal
125 * @wpa_s: %wpa_supplicant network interface data
126 * @sig_name: signal name - InterfaceAdded or InterfaceRemoved
127 * @properties: Whether to add second argument with object properties
128 *
129 * Notify listeners about event related with interface
130 */
131static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
132				       const char *sig_name,
133				       dbus_bool_t properties)
134{
135	struct wpas_dbus_priv *iface;
136	DBusMessage *msg;
137	DBusMessageIter iter;
138
139	iface = wpa_s->global->dbus;
140
141	/* Do nothing if the control interface is not turned on */
142	if (iface == NULL || !wpa_s->dbus_new_path)
143		return;
144
145	msg = dbus_message_new_signal(WPAS_DBUS_NEW_PATH,
146				      WPAS_DBUS_NEW_INTERFACE, sig_name);
147	if (msg == NULL)
148		return;
149
150	dbus_message_iter_init_append(msg, &iter);
151	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
152					    &wpa_s->dbus_new_path) ||
153	    (properties &&
154	     !wpa_dbus_get_object_properties(
155		     iface, wpa_s->dbus_new_path,
156		     WPAS_DBUS_NEW_IFACE_INTERFACE, &iter)))
157		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
158	else
159		dbus_connection_send(iface->con, msg, NULL);
160	dbus_message_unref(msg);
161}
162
163
164/**
165 * wpas_dbus_signal_interface_added - Send a interface created signal
166 * @wpa_s: %wpa_supplicant network interface data
167 *
168 * Notify listeners about creating new interface
169 */
170static void wpas_dbus_signal_interface_added(struct wpa_supplicant *wpa_s)
171{
172	wpas_dbus_signal_interface(wpa_s, "InterfaceAdded", TRUE);
173}
174
175
176/**
177 * wpas_dbus_signal_interface_removed - Send a interface removed signal
178 * @wpa_s: %wpa_supplicant network interface data
179 *
180 * Notify listeners about removing interface
181 */
182static void wpas_dbus_signal_interface_removed(struct wpa_supplicant *wpa_s)
183{
184	wpas_dbus_signal_interface(wpa_s, "InterfaceRemoved", FALSE);
185
186}
187
188
189/**
190 * wpas_dbus_signal_scan_done - send scan done signal
191 * @wpa_s: %wpa_supplicant network interface data
192 * @success: indicates if scanning succeed or failed
193 *
194 * Notify listeners about finishing a scan
195 */
196void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success)
197{
198	struct wpas_dbus_priv *iface;
199	DBusMessage *msg;
200	dbus_bool_t succ;
201
202	iface = wpa_s->global->dbus;
203
204	/* Do nothing if the control interface is not turned on */
205	if (iface == NULL || !wpa_s->dbus_new_path)
206		return;
207
208	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
209				      WPAS_DBUS_NEW_IFACE_INTERFACE,
210				      "ScanDone");
211	if (msg == NULL)
212		return;
213
214	succ = success ? TRUE : FALSE;
215	if (dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &succ,
216				     DBUS_TYPE_INVALID))
217		dbus_connection_send(iface->con, msg, NULL);
218	else
219		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
220	dbus_message_unref(msg);
221}
222
223
224/**
225 * wpas_dbus_signal_bss - Send a BSS related event signal
226 * @wpa_s: %wpa_supplicant network interface data
227 * @bss_obj_path: BSS object path
228 * @sig_name: signal name - BSSAdded or BSSRemoved
229 * @properties: Whether to add second argument with object properties
230 *
231 * Notify listeners about event related with BSS
232 */
233static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
234				 const char *bss_obj_path,
235				 const char *sig_name, dbus_bool_t properties)
236{
237	struct wpas_dbus_priv *iface;
238	DBusMessage *msg;
239	DBusMessageIter iter;
240
241	iface = wpa_s->global->dbus;
242
243	/* Do nothing if the control interface is not turned on */
244	if (iface == NULL || !wpa_s->dbus_new_path)
245		return;
246
247	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
248				      WPAS_DBUS_NEW_IFACE_INTERFACE,
249				      sig_name);
250	if (msg == NULL)
251		return;
252
253	dbus_message_iter_init_append(msg, &iter);
254	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
255					    &bss_obj_path) ||
256	    (properties &&
257	     !wpa_dbus_get_object_properties(iface, bss_obj_path,
258					     WPAS_DBUS_NEW_IFACE_BSS,
259					     &iter)))
260		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
261	else
262		dbus_connection_send(iface->con, msg, NULL);
263	dbus_message_unref(msg);
264}
265
266
267/**
268 * wpas_dbus_signal_bss_added - Send a BSS added signal
269 * @wpa_s: %wpa_supplicant network interface data
270 * @bss_obj_path: new BSS object path
271 *
272 * Notify listeners about adding new BSS
273 */
274static void wpas_dbus_signal_bss_added(struct wpa_supplicant *wpa_s,
275				       const char *bss_obj_path)
276{
277	wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSAdded", TRUE);
278}
279
280
281/**
282 * wpas_dbus_signal_bss_removed - Send a BSS removed signal
283 * @wpa_s: %wpa_supplicant network interface data
284 * @bss_obj_path: BSS object path
285 *
286 * Notify listeners about removing BSS
287 */
288static void wpas_dbus_signal_bss_removed(struct wpa_supplicant *wpa_s,
289					 const char *bss_obj_path)
290{
291	wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSRemoved", FALSE);
292}
293
294
295/**
296 * wpas_dbus_signal_blob - Send a blob related event signal
297 * @wpa_s: %wpa_supplicant network interface data
298 * @name: blob name
299 * @sig_name: signal name - BlobAdded or BlobRemoved
300 *
301 * Notify listeners about event related with blob
302 */
303static void wpas_dbus_signal_blob(struct wpa_supplicant *wpa_s,
304				  const char *name, const char *sig_name)
305{
306	struct wpas_dbus_priv *iface;
307	DBusMessage *msg;
308
309	iface = wpa_s->global->dbus;
310
311	/* Do nothing if the control interface is not turned on */
312	if (iface == NULL || !wpa_s->dbus_new_path)
313		return;
314
315	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
316				      WPAS_DBUS_NEW_IFACE_INTERFACE,
317				      sig_name);
318	if (msg == NULL)
319		return;
320
321	if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
322				     DBUS_TYPE_INVALID))
323		dbus_connection_send(iface->con, msg, NULL);
324	else
325		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
326	dbus_message_unref(msg);
327}
328
329
330/**
331 * wpas_dbus_signal_blob_added - Send a blob added signal
332 * @wpa_s: %wpa_supplicant network interface data
333 * @name: blob name
334 *
335 * Notify listeners about adding a new blob
336 */
337void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
338				 const char *name)
339{
340	wpas_dbus_signal_blob(wpa_s, name, "BlobAdded");
341}
342
343
344/**
345 * wpas_dbus_signal_blob_removed - Send a blob removed signal
346 * @wpa_s: %wpa_supplicant network interface data
347 * @name: blob name
348 *
349 * Notify listeners about removing blob
350 */
351void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
352				   const char *name)
353{
354	wpas_dbus_signal_blob(wpa_s, name, "BlobRemoved");
355}
356
357
358/**
359 * wpas_dbus_signal_network - Send a network related event signal
360 * @wpa_s: %wpa_supplicant network interface data
361 * @id: new network id
362 * @sig_name: signal name - NetworkAdded, NetworkRemoved or NetworkSelected
363 * @properties: determines if add second argument with object properties
364 *
365 * Notify listeners about event related with configured network
366 */
367static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
368				     int id, const char *sig_name,
369				     dbus_bool_t properties)
370{
371	struct wpas_dbus_priv *iface;
372	DBusMessage *msg;
373	DBusMessageIter iter;
374	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
375
376	iface = wpa_s->global->dbus;
377
378	/* Do nothing if the control interface is not turned on */
379	if (iface == NULL || !wpa_s->dbus_new_path)
380		return;
381
382	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
383		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
384		    wpa_s->dbus_new_path, id);
385
386	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
387				      WPAS_DBUS_NEW_IFACE_INTERFACE,
388				      sig_name);
389	if (msg == NULL)
390		return;
391
392	dbus_message_iter_init_append(msg, &iter);
393	path = net_obj_path;
394	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
395					    &path) ||
396	    (properties &&
397	     !wpa_dbus_get_object_properties(
398		     iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
399		     &iter)))
400		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
401	else
402		dbus_connection_send(iface->con, msg, NULL);
403	dbus_message_unref(msg);
404}
405
406
407/**
408 * wpas_dbus_signal_network_added - Send a network added signal
409 * @wpa_s: %wpa_supplicant network interface data
410 * @id: new network id
411 *
412 * Notify listeners about adding new network
413 */
414static void wpas_dbus_signal_network_added(struct wpa_supplicant *wpa_s,
415					   int id)
416{
417	wpas_dbus_signal_network(wpa_s, id, "NetworkAdded", TRUE);
418}
419
420
421/**
422 * wpas_dbus_signal_network_removed - Send a network removed signal
423 * @wpa_s: %wpa_supplicant network interface data
424 * @id: network id
425 *
426 * Notify listeners about removing a network
427 */
428static void wpas_dbus_signal_network_removed(struct wpa_supplicant *wpa_s,
429					     int id)
430{
431	wpas_dbus_signal_network(wpa_s, id, "NetworkRemoved", FALSE);
432}
433
434
435/**
436 * wpas_dbus_signal_network_selected - Send a network selected signal
437 * @wpa_s: %wpa_supplicant network interface data
438 * @id: network id
439 *
440 * Notify listeners about selecting a network
441 */
442void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id)
443{
444	wpas_dbus_signal_network(wpa_s, id, "NetworkSelected", FALSE);
445}
446
447
448/**
449 * wpas_dbus_signal_network_request - Indicate that additional information
450 * (EAP password, etc.) is required to complete the association to this SSID
451 * @wpa_s: %wpa_supplicant network interface data
452 * @rtype: The specific additional information required
453 * @default_text: Optional description of required information
454 *
455 * Request additional information or passwords to complete an association
456 * request.
457 */
458void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
459				      struct wpa_ssid *ssid,
460				      enum wpa_ctrl_req_type rtype,
461				      const char *default_txt)
462{
463	struct wpas_dbus_priv *iface;
464	DBusMessage *msg;
465	DBusMessageIter iter;
466	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
467	const char *field, *txt = NULL, *net_ptr;
468
469	iface = wpa_s->global->dbus;
470
471	/* Do nothing if the control interface is not turned on */
472	if (iface == NULL || !wpa_s->dbus_new_path)
473		return;
474
475	field = wpa_supplicant_ctrl_req_to_string(rtype, default_txt, &txt);
476	if (field == NULL)
477		return;
478
479	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
480				      WPAS_DBUS_NEW_IFACE_INTERFACE,
481				      "NetworkRequest");
482	if (msg == NULL)
483		return;
484
485	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
486		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
487		    wpa_s->dbus_new_path, ssid->id);
488	net_ptr = &net_obj_path[0];
489
490	dbus_message_iter_init_append(msg, &iter);
491	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
492					    &net_ptr) ||
493	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field) ||
494	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
495		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
496	else
497		dbus_connection_send(iface->con, msg, NULL);
498	dbus_message_unref(msg);
499}
500
501
502/**
503 * wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes
504 * @wpa_s: %wpa_supplicant network interface data
505 * @ssid: configured network which Enabled property has changed
506 *
507 * Sends PropertyChanged signals containing new value of Enabled property
508 * for specified network
509 */
510void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
511					      struct wpa_ssid *ssid)
512{
513
514	char path[WPAS_DBUS_OBJECT_PATH_MAX];
515
516	if (!wpa_s->dbus_new_path)
517		return;
518	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
519		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
520		    wpa_s->dbus_new_path, ssid->id);
521
522	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
523				       WPAS_DBUS_NEW_IFACE_NETWORK, "Enabled");
524}
525
526
527#ifdef CONFIG_WPS
528
529/**
530 * wpas_dbus_signal_wps_event_pbc_overlap - Signals PBC overlap WPS event
531 * @wpa_s: %wpa_supplicant network interface data
532 *
533 * Sends Event dbus signal with name "pbc-overlap" and empty dict as arguments
534 */
535void wpas_dbus_signal_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
536{
537
538	DBusMessage *msg;
539	DBusMessageIter iter, dict_iter;
540	struct wpas_dbus_priv *iface;
541	char *key = "pbc-overlap";
542
543	iface = wpa_s->global->dbus;
544
545	/* Do nothing if the control interface is not turned on */
546	if (iface == NULL || !wpa_s->dbus_new_path)
547		return;
548
549	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
550				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
551	if (msg == NULL)
552		return;
553
554	dbus_message_iter_init_append(msg, &iter);
555
556	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
557	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
558	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
559		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
560	else
561		dbus_connection_send(iface->con, msg, NULL);
562
563	dbus_message_unref(msg);
564}
565
566
567/**
568 * wpas_dbus_signal_wps_event_success - Signals Success WPS event
569 * @wpa_s: %wpa_supplicant network interface data
570 *
571 * Sends Event dbus signal with name "success" and empty dict as arguments
572 */
573void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s)
574{
575
576	DBusMessage *msg;
577	DBusMessageIter iter, dict_iter;
578	struct wpas_dbus_priv *iface;
579	char *key = "success";
580
581	iface = wpa_s->global->dbus;
582
583	/* Do nothing if the control interface is not turned on */
584	if (iface == NULL || !wpa_s->dbus_new_path)
585		return;
586
587	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
588				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
589	if (msg == NULL)
590		return;
591
592	dbus_message_iter_init_append(msg, &iter);
593
594	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
595	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
596	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
597		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
598	else
599		dbus_connection_send(iface->con, msg, NULL);
600
601	dbus_message_unref(msg);
602}
603
604
605/**
606 * wpas_dbus_signal_wps_event_fail - Signals Fail WPS event
607 * @wpa_s: %wpa_supplicant network interface data
608 * @fail: WPS failure information
609 *
610 * Sends Event dbus signal with name "fail" and dictionary containing
611 * "msg field with fail message number (int32) as arguments
612 */
613void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s,
614				     struct wps_event_fail *fail)
615{
616
617	DBusMessage *msg;
618	DBusMessageIter iter, dict_iter;
619	struct wpas_dbus_priv *iface;
620	char *key = "fail";
621
622	iface = wpa_s->global->dbus;
623
624	/* Do nothing if the control interface is not turned on */
625	if (iface == NULL || !wpa_s->dbus_new_path)
626		return;
627
628	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
629				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
630	if (msg == NULL)
631		return;
632
633	dbus_message_iter_init_append(msg, &iter);
634
635	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
636	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
637	    !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
638	    !wpa_dbus_dict_append_int32(&dict_iter, "config_error",
639					fail->config_error) ||
640	    !wpa_dbus_dict_append_int32(&dict_iter, "error_indication",
641					fail->error_indication) ||
642	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
643		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
644	else
645		dbus_connection_send(iface->con, msg, NULL);
646
647	dbus_message_unref(msg);
648}
649
650
651/**
652 * wpas_dbus_signal_wps_event_m2d - Signals M2D WPS event
653 * @wpa_s: %wpa_supplicant network interface data
654 * @m2d: M2D event data information
655 *
656 * Sends Event dbus signal with name "m2d" and dictionary containing
657 * fields of wps_event_m2d structure.
658 */
659void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
660				    struct wps_event_m2d *m2d)
661{
662
663	DBusMessage *msg;
664	DBusMessageIter iter, dict_iter;
665	struct wpas_dbus_priv *iface;
666	char *key = "m2d";
667
668	iface = wpa_s->global->dbus;
669
670	/* Do nothing if the control interface is not turned on */
671	if (iface == NULL || !wpa_s->dbus_new_path)
672		return;
673
674	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
675				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
676	if (msg == NULL)
677		return;
678
679	dbus_message_iter_init_append(msg, &iter);
680
681	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
682	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
683	    !wpa_dbus_dict_append_uint16(&dict_iter, "config_methods",
684					 m2d->config_methods) ||
685	    !wpa_dbus_dict_append_byte_array(&dict_iter, "manufacturer",
686					     (const char *) m2d->manufacturer,
687					     m2d->manufacturer_len) ||
688	    !wpa_dbus_dict_append_byte_array(&dict_iter, "model_name",
689					     (const char *) m2d->model_name,
690					     m2d->model_name_len) ||
691	    !wpa_dbus_dict_append_byte_array(&dict_iter, "model_number",
692					     (const char *) m2d->model_number,
693					     m2d->model_number_len) ||
694	    !wpa_dbus_dict_append_byte_array(&dict_iter, "serial_number",
695					     (const char *)
696					     m2d->serial_number,
697					     m2d->serial_number_len) ||
698	    !wpa_dbus_dict_append_byte_array(&dict_iter, "dev_name",
699					     (const char *) m2d->dev_name,
700					     m2d->dev_name_len) ||
701	    !wpa_dbus_dict_append_byte_array(&dict_iter, "primary_dev_type",
702					     (const char *)
703					     m2d->primary_dev_type, 8) ||
704	    !wpa_dbus_dict_append_uint16(&dict_iter, "config_error",
705					 m2d->config_error) ||
706	    !wpa_dbus_dict_append_uint16(&dict_iter, "dev_password_id",
707					 m2d->dev_password_id) ||
708	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
709		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
710	else
711		dbus_connection_send(iface->con, msg, NULL);
712
713	dbus_message_unref(msg);
714}
715
716
717/**
718 * wpas_dbus_signal_wps_cred - Signals new credentials
719 * @wpa_s: %wpa_supplicant network interface data
720 * @cred: WPS Credential information
721 *
722 * Sends signal with credentials in directory argument
723 */
724void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
725			       const struct wps_credential *cred)
726{
727	DBusMessage *msg;
728	DBusMessageIter iter, dict_iter;
729	struct wpas_dbus_priv *iface;
730	char *auth_type[5]; /* we have five possible authentication types */
731	int at_num = 0;
732	char *encr_type[3]; /* we have three possible encryption types */
733	int et_num = 0;
734
735	iface = wpa_s->global->dbus;
736
737	/* Do nothing if the control interface is not turned on */
738	if (iface == NULL || !wpa_s->dbus_new_path)
739		return;
740
741	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
742				      WPAS_DBUS_NEW_IFACE_WPS,
743				      "Credentials");
744	if (msg == NULL)
745		return;
746
747	dbus_message_iter_init_append(msg, &iter);
748	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
749		goto nomem;
750
751	if (cred->auth_type & WPS_AUTH_OPEN)
752		auth_type[at_num++] = "open";
753	if (cred->auth_type & WPS_AUTH_WPAPSK)
754		auth_type[at_num++] = "wpa-psk";
755	if (cred->auth_type & WPS_AUTH_WPA)
756		auth_type[at_num++] = "wpa-eap";
757	if (cred->auth_type & WPS_AUTH_WPA2)
758		auth_type[at_num++] = "wpa2-eap";
759	if (cred->auth_type & WPS_AUTH_WPA2PSK)
760		auth_type[at_num++] = "wpa2-psk";
761
762	if (cred->encr_type & WPS_ENCR_NONE)
763		encr_type[et_num++] = "none";
764	if (cred->encr_type & WPS_ENCR_TKIP)
765		encr_type[et_num++] = "tkip";
766	if (cred->encr_type & WPS_ENCR_AES)
767		encr_type[et_num++] = "aes";
768
769	if ((wpa_s->current_ssid &&
770	     !wpa_dbus_dict_append_byte_array(
771		     &dict_iter, "BSSID",
772		     (const char *) wpa_s->current_ssid->bssid, ETH_ALEN)) ||
773	    !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
774					     (const char *) cred->ssid,
775					     cred->ssid_len) ||
776	    !wpa_dbus_dict_append_string_array(&dict_iter, "AuthType",
777					       (const char **) auth_type,
778					       at_num) ||
779	    !wpa_dbus_dict_append_string_array(&dict_iter, "EncrType",
780					       (const char **) encr_type,
781					       et_num) ||
782	    !wpa_dbus_dict_append_byte_array(&dict_iter, "Key",
783					     (const char *) cred->key,
784					     cred->key_len) ||
785	    !wpa_dbus_dict_append_uint32(&dict_iter, "KeyIndex",
786					 cred->key_idx) ||
787	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
788		goto nomem;
789
790	dbus_connection_send(iface->con, msg, NULL);
791
792nomem:
793	dbus_message_unref(msg);
794}
795
796#endif /* CONFIG_WPS */
797
798
799#ifdef CONFIG_MESH
800
801void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s,
802					 struct wpa_ssid *ssid)
803{
804	struct wpas_dbus_priv *iface;
805	DBusMessage *msg;
806	DBusMessageIter iter, dict_iter;
807
808	iface = wpa_s->global->dbus;
809
810	/* Do nothing if the control interface is not turned on */
811	if (!iface || !wpa_s->dbus_new_path)
812		return;
813
814	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
815				      WPAS_DBUS_NEW_IFACE_MESH,
816				      "MeshGroupStarted");
817	if (!msg)
818		return;
819
820	dbus_message_iter_init_append(msg, &iter);
821	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
822	    !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
823					     (const char *) ssid->ssid,
824					     ssid->ssid_len) ||
825	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
826		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
827	else
828		dbus_connection_send(iface->con, msg, NULL);
829	dbus_message_unref(msg);
830}
831
832
833void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s,
834					 const u8 *meshid, u8 meshid_len,
835					 int reason)
836{
837	struct wpas_dbus_priv *iface;
838	DBusMessage *msg;
839	DBusMessageIter iter, dict_iter;
840
841	iface = wpa_s->global->dbus;
842
843	/* Do nothing if the control interface is not turned on */
844	if (!iface || !wpa_s->dbus_new_path)
845		return;
846
847	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
848				      WPAS_DBUS_NEW_IFACE_MESH,
849				      "MeshGroupRemoved");
850	if (!msg)
851		return;
852
853	dbus_message_iter_init_append(msg, &iter);
854	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
855	    !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
856					     (const char *) meshid,
857					     meshid_len) ||
858	    !wpa_dbus_dict_append_int32(&dict_iter, "DisconnectReason",
859					reason) ||
860	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
861		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
862	else
863		dbus_connection_send(iface->con, msg, NULL);
864	dbus_message_unref(msg);
865}
866
867
868void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s,
869					  const u8 *peer_addr)
870{
871	struct wpas_dbus_priv *iface;
872	DBusMessage *msg;
873	DBusMessageIter iter, dict_iter;
874
875	iface = wpa_s->global->dbus;
876
877	/* Do nothing if the control interface is not turned on */
878	if (!iface || !wpa_s->dbus_new_path)
879		return;
880
881	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
882				      WPAS_DBUS_NEW_IFACE_MESH,
883				      "MeshPeerConnected");
884	if (!msg)
885		return;
886
887	dbus_message_iter_init_append(msg, &iter);
888	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
889	    !wpa_dbus_dict_append_byte_array(&dict_iter, "PeerAddress",
890					     (const char *) peer_addr,
891					     ETH_ALEN) ||
892	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
893		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
894	else
895		dbus_connection_send(iface->con, msg, NULL);
896	dbus_message_unref(msg);
897}
898
899
900void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
901					     const u8 *peer_addr, int reason)
902{
903	struct wpas_dbus_priv *iface;
904	DBusMessage *msg;
905	DBusMessageIter iter, dict_iter;
906
907	iface = wpa_s->global->dbus;
908
909	/* Do nothing if the control interface is not turned on */
910	if (!iface || !wpa_s->dbus_new_path)
911		return;
912
913	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
914				      WPAS_DBUS_NEW_IFACE_MESH,
915				      "MeshPeerDisconnected");
916	if (!msg)
917		return;
918
919	dbus_message_iter_init_append(msg, &iter);
920	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
921	    !wpa_dbus_dict_append_byte_array(&dict_iter, "PeerAddress",
922					     (const char *) peer_addr,
923					     ETH_ALEN) ||
924	    !wpa_dbus_dict_append_int32(&dict_iter, "DisconnectReason",
925					reason) ||
926	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
927		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
928	else
929		dbus_connection_send(iface->con, msg, NULL);
930	dbus_message_unref(msg);
931}
932
933#endif /* CONFIG_MESH */
934
935
936void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
937				    int depth, const char *subject,
938				    const char *altsubject[],
939				    int num_altsubject,
940				    const char *cert_hash,
941				    const struct wpabuf *cert)
942{
943	struct wpas_dbus_priv *iface;
944	DBusMessage *msg;
945	DBusMessageIter iter, dict_iter;
946
947	iface = wpa_s->global->dbus;
948
949	/* Do nothing if the control interface is not turned on */
950	if (iface == NULL || !wpa_s->dbus_new_path)
951		return;
952
953	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
954				      WPAS_DBUS_NEW_IFACE_INTERFACE,
955				      "Certification");
956	if (msg == NULL)
957		return;
958
959	dbus_message_iter_init_append(msg, &iter);
960	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
961	    !wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
962	    !wpa_dbus_dict_append_string(&dict_iter, "subject", subject) ||
963	    (altsubject && num_altsubject &&
964	     !wpa_dbus_dict_append_string_array(&dict_iter, "altsubject",
965						altsubject, num_altsubject)) ||
966	    (cert_hash &&
967	     !wpa_dbus_dict_append_string(&dict_iter, "cert_hash",
968					  cert_hash)) ||
969	    (cert &&
970	     !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
971					      wpabuf_head(cert),
972					      wpabuf_len(cert))) ||
973	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
974		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
975	else
976		dbus_connection_send(iface->con, msg, NULL);
977	dbus_message_unref(msg);
978}
979
980
981void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
982				 const char *status, const char *parameter)
983{
984	struct wpas_dbus_priv *iface;
985	DBusMessage *msg;
986	DBusMessageIter iter;
987
988	iface = wpa_s->global->dbus;
989
990	/* Do nothing if the control interface is not turned on */
991	if (iface == NULL || !wpa_s->dbus_new_path)
992		return;
993
994	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
995				      WPAS_DBUS_NEW_IFACE_INTERFACE,
996				      "EAP");
997	if (msg == NULL)
998		return;
999
1000	dbus_message_iter_init_append(msg, &iter);
1001
1002	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status) ||
1003	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
1004					    &parameter))
1005		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1006	else
1007		dbus_connection_send(iface->con, msg, NULL);
1008	dbus_message_unref(msg);
1009}
1010
1011
1012/**
1013 * wpas_dbus_signal_sta - Send a station related event signal
1014 * @wpa_s: %wpa_supplicant network interface data
1015 * @sta: station mac address
1016 * @sig_name: signal name - StaAuthorized or StaDeauthorized
1017 *
1018 * Notify listeners about event related with station
1019 */
1020static void wpas_dbus_signal_sta(struct wpa_supplicant *wpa_s,
1021				 const u8 *sta, const char *sig_name)
1022{
1023	struct wpas_dbus_priv *iface;
1024	DBusMessage *msg;
1025	char sta_mac[WPAS_DBUS_OBJECT_PATH_MAX];
1026	char *dev_mac;
1027
1028	os_snprintf(sta_mac, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(sta));
1029	dev_mac = sta_mac;
1030
1031	iface = wpa_s->global->dbus;
1032
1033	/* Do nothing if the control interface is not turned on */
1034	if (iface == NULL || !wpa_s->dbus_new_path)
1035		return;
1036
1037	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1038				      WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
1039	if (msg == NULL)
1040		return;
1041
1042	if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &dev_mac,
1043				     DBUS_TYPE_INVALID))
1044		dbus_connection_send(iface->con, msg, NULL);
1045	else
1046		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1047	dbus_message_unref(msg);
1048
1049	wpa_printf(MSG_DEBUG, "dbus: Station MAC address '%s' '%s'",
1050		   sta_mac, sig_name);
1051}
1052
1053
1054/**
1055 * wpas_dbus_signal_sta_authorized - Send a STA authorized signal
1056 * @wpa_s: %wpa_supplicant network interface data
1057 * @sta: station mac address
1058 *
1059 * Notify listeners a new station has been authorized
1060 */
1061void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
1062				     const u8 *sta)
1063{
1064	wpas_dbus_signal_sta(wpa_s, sta, "StaAuthorized");
1065}
1066
1067
1068/**
1069 * wpas_dbus_signal_sta_deauthorized - Send a STA deauthorized signal
1070 * @wpa_s: %wpa_supplicant network interface data
1071 * @sta: station mac address
1072 *
1073 * Notify listeners a station has been deauthorized
1074 */
1075void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
1076				       const u8 *sta)
1077{
1078	wpas_dbus_signal_sta(wpa_s, sta, "StaDeauthorized");
1079}
1080
1081
1082/**
1083 * wpas_dbus_signal_station - Send an event signal related to a station object
1084 * @wpa_s: %wpa_supplicant network interface data
1085 * @station_obj_path: Station object path
1086 * @sig_name: signal name - StationAdded or StationRemoved
1087 * @properties: Whether to add second argument with object properties
1088 *
1089 * Notify listeners about event related with station.
1090 */
1091static void wpas_dbus_signal_station(struct wpa_supplicant *wpa_s,
1092				     const char *station_obj_path,
1093				     const char *sig_name,
1094				     dbus_bool_t properties)
1095{
1096	struct wpas_dbus_priv *iface;
1097	DBusMessage *msg;
1098	DBusMessageIter iter;
1099
1100	iface = wpa_s->global->dbus;
1101
1102	/* Do nothing if the control interface is not turned on */
1103	if (!iface || !wpa_s->dbus_new_path)
1104		return;
1105
1106	wpa_printf(MSG_DEBUG, "dbus: STA signal %s", sig_name);
1107	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1108				      WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
1109	if (!msg)
1110		return;
1111
1112	dbus_message_iter_init_append(msg, &iter);
1113	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
1114					    &station_obj_path) ||
1115	    (properties &&
1116	     !wpa_dbus_get_object_properties(iface, station_obj_path,
1117					     WPAS_DBUS_NEW_IFACE_STA,
1118					     &iter)))
1119		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1120	else
1121		dbus_connection_send(iface->con, msg, NULL);
1122	dbus_message_unref(msg);
1123}
1124
1125
1126/**
1127 * wpas_dbus_signal_station_added - Send a Station added signal
1128 * @wpa_s: %wpa_supplicant network interface data
1129 * @station_obj_path: new Station object path
1130 *
1131 * Notify listeners about adding new Station
1132 */
1133static void wpas_dbus_signal_station_added(struct wpa_supplicant *wpa_s,
1134					   const char *station_obj_path)
1135{
1136	wpas_dbus_signal_station(wpa_s, station_obj_path, "StationAdded", TRUE);
1137}
1138
1139
1140/**
1141 * wpas_dbus_signal_station_removed - Send a Station removed signal
1142 * @wpa_s: %wpa_supplicant network interface data
1143 * @station_obj_path: Station object path
1144 *
1145 * Notify listeners about removing Station
1146 */
1147static void wpas_dbus_signal_station_removed(struct wpa_supplicant *wpa_s,
1148					     const char *station_obj_path)
1149{
1150	wpas_dbus_signal_station(wpa_s, station_obj_path, "StationRemoved",
1151				 FALSE);
1152}
1153
1154
1155#ifdef CONFIG_P2P
1156
1157/**
1158 * wpas_dbus_signal_p2p_group_removed - Signals P2P group was removed
1159 * @wpa_s: %wpa_supplicant network interface data
1160 * @role: role of this device (client or GO)
1161 * Sends signal with i/f name and role as string arguments
1162 */
1163void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
1164					const char *role)
1165{
1166	DBusMessage *msg;
1167	DBusMessageIter iter, dict_iter;
1168	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
1169	struct wpa_supplicant *parent;
1170
1171	/* Do nothing if the control interface is not turned on */
1172	if (iface == NULL)
1173		return;
1174
1175	parent = wpa_s->parent;
1176	if (parent->p2p_mgmt)
1177		parent = parent->parent;
1178
1179	if (!wpa_s->dbus_groupobj_path || !wpa_s->dbus_new_path ||
1180	    !parent->dbus_new_path)
1181		return;
1182
1183	msg = dbus_message_new_signal(parent->dbus_new_path,
1184				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1185				      "GroupFinished");
1186	if (msg == NULL)
1187		return;
1188
1189	dbus_message_iter_init_append(msg, &iter);
1190	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1191	    !wpa_dbus_dict_append_object_path(&dict_iter,
1192					      "interface_object",
1193					      wpa_s->dbus_new_path) ||
1194	    !wpa_dbus_dict_append_string(&dict_iter, "role", role) ||
1195	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
1196					      wpa_s->dbus_groupobj_path) ||
1197	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
1198		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1199	else
1200		dbus_connection_send(iface->con, msg, NULL);
1201	dbus_message_unref(msg);
1202}
1203
1204
1205/**
1206 * wpas_dbus_signal_p2p_provision_discovery - Signals various PD events
1207 *
1208 * @dev_addr - who sent the request or responded to our request.
1209 * @request - Will be 1 if request, 0 for response.
1210 * @status - valid only in case of response
1211 * @config_methods - wps config methods
1212 * @generated_pin - pin to be displayed in case of WPS_CONFIG_DISPLAY method
1213 *
1214 * Sends following provision discovery related events:
1215 *	ProvisionDiscoveryRequestDisplayPin
1216 *	ProvisionDiscoveryResponseDisplayPin
1217 *	ProvisionDiscoveryRequestEnterPin
1218 *	ProvisionDiscoveryResponseEnterPin
1219 *	ProvisionDiscoveryPBCRequest
1220 *	ProvisionDiscoveryPBCResponse
1221 *
1222 *	TODO::
1223 *	ProvisionDiscoveryFailure (timeout case)
1224 */
1225void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
1226					      const u8 *dev_addr, int request,
1227					      enum p2p_prov_disc_status status,
1228					      u16 config_methods,
1229					      unsigned int generated_pin)
1230{
1231	DBusMessage *msg;
1232	DBusMessageIter iter;
1233	struct wpas_dbus_priv *iface;
1234	char *_signal;
1235	int add_pin = 0;
1236	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1237	int error_ret = 1;
1238	char pin[9], *p_pin = NULL;
1239
1240	iface = wpa_s->global->dbus;
1241
1242	/* Do nothing if the control interface is not turned on */
1243	if (iface == NULL)
1244		return;
1245
1246	if (wpa_s->p2p_mgmt)
1247		wpa_s = wpa_s->parent;
1248	if (!wpa_s->dbus_new_path)
1249		return;
1250
1251	if (request || !status) {
1252		if (config_methods & WPS_CONFIG_DISPLAY)
1253			_signal = request ?
1254				 "ProvisionDiscoveryRequestDisplayPin" :
1255				 "ProvisionDiscoveryResponseEnterPin";
1256		else if (config_methods & WPS_CONFIG_KEYPAD)
1257			_signal = request ?
1258				 "ProvisionDiscoveryRequestEnterPin" :
1259				 "ProvisionDiscoveryResponseDisplayPin";
1260		else if (config_methods & WPS_CONFIG_PUSHBUTTON)
1261			_signal = request ? "ProvisionDiscoveryPBCRequest" :
1262				   "ProvisionDiscoveryPBCResponse";
1263		else
1264			return; /* Unknown or un-supported method */
1265	} else {
1266		/* Explicit check for failure response */
1267		_signal = "ProvisionDiscoveryFailure";
1268	}
1269
1270	add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
1271		   (!request && !status &&
1272			(config_methods & WPS_CONFIG_KEYPAD)));
1273
1274	if (add_pin) {
1275		os_snprintf(pin, sizeof(pin), "%08d", generated_pin);
1276		p_pin = pin;
1277	}
1278
1279	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1280				      WPAS_DBUS_NEW_IFACE_P2PDEVICE, _signal);
1281	if (msg == NULL)
1282		return;
1283
1284	/* Check if this is a known peer */
1285	if (!p2p_peer_known(wpa_s->global->p2p, dev_addr))
1286		goto error;
1287
1288	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1289			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1290			COMPACT_MACSTR,
1291			wpa_s->dbus_new_path, MAC2STR(dev_addr));
1292
1293	path = peer_obj_path;
1294
1295	dbus_message_iter_init_append(msg, &iter);
1296
1297	if (!dbus_message_iter_append_basic(&iter,
1298					    DBUS_TYPE_OBJECT_PATH,
1299					    &path))
1300			goto error;
1301
1302	if (!request && status)
1303		/* Attach status to ProvisionDiscoveryFailure */
1304		error_ret = !dbus_message_iter_append_basic(&iter,
1305						    DBUS_TYPE_INT32,
1306						    &status);
1307	else
1308		error_ret = (add_pin &&
1309				 !dbus_message_iter_append_basic(&iter,
1310							DBUS_TYPE_STRING,
1311							&p_pin));
1312
1313error:
1314	if (!error_ret)
1315		dbus_connection_send(iface->con, msg, NULL);
1316	else
1317		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1318
1319	dbus_message_unref(msg);
1320}
1321
1322
1323/**
1324 * wpas_dbus_signal_p2p_go_neg_req - Signal P2P GO Negotiation Request RX
1325 * @wpa_s: %wpa_supplicant network interface data
1326 * @src: Source address of the message triggering this notification
1327 * @dev_passwd_id: WPS Device Password Id
1328 * @go_intent: Peer's GO Intent value
1329 *
1330 * Sends signal to notify that a peer P2P Device is requesting group owner
1331 * negotiation with us.
1332 */
1333void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
1334				     const u8 *src, u16 dev_passwd_id,
1335				     u8 go_intent)
1336{
1337	DBusMessage *msg;
1338	DBusMessageIter iter;
1339	struct wpas_dbus_priv *iface;
1340	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1341
1342	iface = wpa_s->global->dbus;
1343
1344	/* Do nothing if the control interface is not turned on */
1345	if (iface == NULL)
1346		return;
1347
1348	if (wpa_s->p2p_mgmt)
1349		wpa_s = wpa_s->parent;
1350	if (!wpa_s->dbus_new_path)
1351		return;
1352
1353	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1354		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1355		    wpa_s->dbus_new_path, MAC2STR(src));
1356	path = peer_obj_path;
1357
1358	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1359				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1360				      "GONegotiationRequest");
1361	if (msg == NULL)
1362		return;
1363
1364	dbus_message_iter_init_append(msg, &iter);
1365
1366	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
1367					    &path) ||
1368	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
1369					    &dev_passwd_id) ||
1370	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BYTE,
1371					    &go_intent))
1372		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1373	else
1374		dbus_connection_send(iface->con, msg, NULL);
1375
1376	dbus_message_unref(msg);
1377}
1378
1379
1380static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
1381					const struct wpa_ssid *ssid,
1382					char *group_obj_path)
1383{
1384	char group_name[3];
1385
1386	if (!wpa_s->dbus_new_path ||
1387	    os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
1388		return -1;
1389
1390	os_memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
1391	group_name[2] = '\0';
1392
1393	os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1394		    "%s/" WPAS_DBUS_NEW_P2P_GROUPS_PART "/%s",
1395		    wpa_s->dbus_new_path, group_name);
1396
1397	return 0;
1398}
1399
1400
1401struct group_changed_data {
1402	struct wpa_supplicant *wpa_s;
1403	struct p2p_peer_info *info;
1404};
1405
1406
1407static int match_group_where_peer_is_client(struct p2p_group *group,
1408					    void *user_data)
1409{
1410	struct group_changed_data *data = user_data;
1411	const struct p2p_group_config *cfg;
1412	struct wpa_supplicant *wpa_s_go;
1413
1414	if (!p2p_group_is_client_connected(group, data->info->p2p_device_addr))
1415		return 1;
1416
1417	cfg = p2p_group_get_config(group);
1418
1419	wpa_s_go = wpas_get_p2p_go_iface(data->wpa_s, cfg->ssid,
1420					 cfg->ssid_len);
1421	if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
1422		wpas_dbus_signal_peer_groups_changed(
1423			data->wpa_s->p2pdev, data->info->p2p_device_addr);
1424		return 0;
1425	}
1426
1427	return 1;
1428}
1429
1430
1431static void signal_peer_groups_changed(struct p2p_peer_info *info,
1432				       void *user_data)
1433{
1434	struct group_changed_data *data = user_data;
1435	struct wpa_supplicant *wpa_s_go;
1436
1437	wpa_s_go = wpas_get_p2p_client_iface(data->wpa_s,
1438					     info->p2p_device_addr);
1439	if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
1440		wpas_dbus_signal_peer_groups_changed(data->wpa_s->p2pdev,
1441						     info->p2p_device_addr);
1442		return;
1443	}
1444
1445	data->info = info;
1446	p2p_loop_on_all_groups(data->wpa_s->global->p2p,
1447			       match_group_where_peer_is_client, data);
1448	data->info = NULL;
1449}
1450
1451
1452static void peer_groups_changed(struct wpa_supplicant *wpa_s)
1453{
1454	struct group_changed_data data;
1455
1456	os_memset(&data, 0, sizeof(data));
1457	data.wpa_s = wpa_s;
1458
1459	p2p_loop_on_known_peers(wpa_s->global->p2p,
1460				signal_peer_groups_changed, &data);
1461}
1462
1463
1464/**
1465 * wpas_dbus_signal_p2p_group_started - Signals P2P group has
1466 * started. Emitted when a group is successfully started
1467 * irrespective of the role (client/GO) of the current device
1468 *
1469 * @wpa_s: %wpa_supplicant network interface data
1470 * @client: this device is P2P client
1471 * @persistent: 0 - non persistent group, 1 - persistent group
1472 * @ip: When group role is client, it contains local IP address, netmask, and
1473 *	GO's IP address, if assigned; otherwise, NULL
1474 */
1475void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
1476					int client, int persistent,
1477					const u8 *ip)
1478{
1479	DBusMessage *msg;
1480	DBusMessageIter iter, dict_iter;
1481	struct wpas_dbus_priv *iface;
1482	struct wpa_supplicant *parent;
1483
1484	parent = wpa_s->parent;
1485	if (parent->p2p_mgmt)
1486		parent = parent->parent;
1487
1488	iface = parent->global->dbus;
1489
1490	/* Do nothing if the control interface is not turned on */
1491	if (iface == NULL || !parent->dbus_new_path || !wpa_s->dbus_new_path)
1492		return;
1493
1494	if (wpa_s->dbus_groupobj_path == NULL)
1495		return;
1496
1497	/* New interface has been created for this group */
1498	msg = dbus_message_new_signal(parent->dbus_new_path,
1499				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1500				      "GroupStarted");
1501	if (msg == NULL)
1502		return;
1503
1504	dbus_message_iter_init_append(msg, &iter);
1505	/*
1506	 * In case the device supports creating a separate interface the
1507	 * DBus client will need to know the object path for the interface
1508	 * object this group was created on, so include it here.
1509	 */
1510	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1511	    !wpa_dbus_dict_append_object_path(&dict_iter,
1512					      "interface_object",
1513					      wpa_s->dbus_new_path) ||
1514	    !wpa_dbus_dict_append_string(&dict_iter, "role",
1515					 client ? "client" : "GO") ||
1516	    !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) ||
1517	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
1518					      wpa_s->dbus_groupobj_path) ||
1519	    (ip &&
1520	     (!wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddr",
1521					       (char *) ip, 4) ||
1522	      !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
1523					       (char *) ip + 4, 4) ||
1524	      !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
1525					       (char *) ip + 8, 4))) ||
1526	    !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
1527		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1528	} else {
1529		dbus_connection_send(iface->con, msg, NULL);
1530		if (client)
1531			peer_groups_changed(wpa_s);
1532	}
1533	dbus_message_unref(msg);
1534}
1535
1536
1537/**
1538 * wpas_dbus_signal_p2p_go_neg_resp - Emit GONegotiation Success/Failure signal
1539 * @wpa_s: %wpa_supplicant network interface data
1540 * @res: Result of the GO Neg Request
1541 */
1542void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
1543				      struct p2p_go_neg_results *res)
1544{
1545	DBusMessage *msg;
1546	DBusMessageIter iter, dict_iter;
1547	DBusMessageIter iter_dict_entry, iter_dict_val, iter_dict_array;
1548	struct wpas_dbus_priv *iface;
1549	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1550	dbus_int32_t freqs[P2P_MAX_CHANNELS];
1551	dbus_int32_t *f_array = freqs;
1552
1553
1554	iface = wpa_s->global->dbus;
1555
1556	if (wpa_s->p2p_mgmt)
1557		wpa_s = wpa_s->parent;
1558
1559	os_memset(freqs, 0, sizeof(freqs));
1560	/* Do nothing if the control interface is not turned on */
1561	if (iface == NULL || !wpa_s->dbus_new_path)
1562		return;
1563
1564	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1565		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1566		    wpa_s->dbus_new_path, MAC2STR(res->peer_device_addr));
1567	path = peer_obj_path;
1568
1569	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1570				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1571				      res->status ? "GONegotiationFailure" :
1572						    "GONegotiationSuccess");
1573	if (msg == NULL)
1574		return;
1575
1576	dbus_message_iter_init_append(msg, &iter);
1577	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1578	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
1579					      path) ||
1580	    !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
1581		goto err;
1582
1583	if (!res->status) {
1584		int i = 0;
1585		int freq_list_num = 0;
1586
1587		if ((res->role_go &&
1588		     !wpa_dbus_dict_append_string(&dict_iter, "passphrase",
1589						  res->passphrase)) ||
1590		    !wpa_dbus_dict_append_string(&dict_iter, "role_go",
1591						 res->role_go ? "GO" :
1592						 "client") ||
1593		    !wpa_dbus_dict_append_int32(&dict_iter, "frequency",
1594						res->freq) ||
1595		    !wpa_dbus_dict_append_byte_array(&dict_iter, "ssid",
1596						     (const char *) res->ssid,
1597						     res->ssid_len) ||
1598		    !wpa_dbus_dict_append_byte_array(&dict_iter,
1599						     "peer_device_addr",
1600						     (const char *)
1601						     res->peer_device_addr,
1602						     ETH_ALEN) ||
1603		    !wpa_dbus_dict_append_byte_array(&dict_iter,
1604						     "peer_interface_addr",
1605						     (const char *)
1606						     res->peer_interface_addr,
1607						     ETH_ALEN) ||
1608		    !wpa_dbus_dict_append_string(&dict_iter, "wps_method",
1609						 p2p_wps_method_text(
1610							 res->wps_method)))
1611			goto err;
1612
1613		for (i = 0; i < P2P_MAX_CHANNELS; i++) {
1614			if (res->freq_list[i]) {
1615				freqs[i] = res->freq_list[i];
1616				freq_list_num++;
1617			}
1618		}
1619
1620		if (!wpa_dbus_dict_begin_array(&dict_iter,
1621					       "frequency_list",
1622					       DBUS_TYPE_INT32_AS_STRING,
1623					       &iter_dict_entry,
1624					       &iter_dict_val,
1625					       &iter_dict_array) ||
1626		    !dbus_message_iter_append_fixed_array(&iter_dict_array,
1627							  DBUS_TYPE_INT32,
1628							  &f_array,
1629							  freq_list_num) ||
1630		    !wpa_dbus_dict_end_array(&dict_iter,
1631					     &iter_dict_entry,
1632					     &iter_dict_val,
1633					     &iter_dict_array) ||
1634		    !wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
1635						res->persistent_group) ||
1636		    !wpa_dbus_dict_append_uint32(&dict_iter,
1637						 "peer_config_timeout",
1638						 res->peer_config_timeout))
1639			goto err;
1640	}
1641
1642	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
1643		goto err;
1644
1645	dbus_connection_send(iface->con, msg, NULL);
1646err:
1647	dbus_message_unref(msg);
1648}
1649
1650
1651/**
1652 * wpas_dbus_signal_p2p_invitation_result - Emit InvitationResult signal
1653 * @wpa_s: %wpa_supplicant network interface data
1654 * @status: Status of invitation process
1655 * @bssid: Basic Service Set Identifier
1656 */
1657void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
1658					    int status, const u8 *bssid)
1659{
1660	DBusMessage *msg;
1661	DBusMessageIter iter, dict_iter;
1662	struct wpas_dbus_priv *iface;
1663
1664	wpa_printf(MSG_DEBUG, "%s", __func__);
1665
1666	iface = wpa_s->global->dbus;
1667	/* Do nothing if the control interface is not turned on */
1668	if (iface == NULL)
1669		return;
1670
1671	if (wpa_s->p2p_mgmt)
1672		wpa_s = wpa_s->parent;
1673	if (!wpa_s->dbus_new_path)
1674		return;
1675
1676	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1677				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1678				      "InvitationResult");
1679
1680	if (msg == NULL)
1681		return;
1682
1683	dbus_message_iter_init_append(msg, &iter);
1684	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1685	    !wpa_dbus_dict_append_int32(&dict_iter, "status", status) ||
1686	    (bssid &&
1687	     !wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
1688					      (const char *) bssid,
1689					      ETH_ALEN)) ||
1690	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
1691		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1692	else
1693		dbus_connection_send(iface->con, msg, NULL);
1694	dbus_message_unref(msg);
1695}
1696
1697
1698/**
1699 *
1700 * Method to emit a signal for a peer joining the group.
1701 * The signal will carry path to the group member object
1702 * constructed using p2p i/f addr used for connecting.
1703 *
1704 * @wpa_s: %wpa_supplicant network interface data
1705 * @peer_addr: P2P Device Address of the peer joining the group
1706 */
1707void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
1708				      const u8 *peer_addr)
1709{
1710	struct wpas_dbus_priv *iface;
1711	DBusMessage *msg;
1712	DBusMessageIter iter;
1713	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1714	struct wpa_supplicant *parent;
1715
1716	iface = wpa_s->global->dbus;
1717
1718	/* Do nothing if the control interface is not turned on */
1719	if (iface == NULL)
1720		return;
1721
1722	if (!wpa_s->dbus_groupobj_path)
1723		return;
1724
1725	parent = wpa_s->parent;
1726	if (parent->p2p_mgmt)
1727		parent = parent->parent;
1728	if (!parent->dbus_new_path)
1729		return;
1730
1731	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1732			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1733			COMPACT_MACSTR,
1734			parent->dbus_new_path, MAC2STR(peer_addr));
1735
1736	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
1737				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
1738				      "PeerJoined");
1739	if (msg == NULL)
1740		return;
1741
1742	dbus_message_iter_init_append(msg, &iter);
1743	path = peer_obj_path;
1744	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
1745					    &path)) {
1746		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1747	} else {
1748		dbus_connection_send(iface->con, msg, NULL);
1749		wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
1750	}
1751	dbus_message_unref(msg);
1752}
1753
1754
1755/**
1756 *
1757 * Method to emit a signal for a peer disconnecting the group.
1758 * The signal will carry path to the group member object
1759 * constructed using the P2P Device Address of the peer.
1760 *
1761 * @wpa_s: %wpa_supplicant network interface data
1762 * @peer_addr: P2P Device Address of the peer joining the group
1763 */
1764void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
1765					    const u8 *peer_addr)
1766{
1767	struct wpas_dbus_priv *iface;
1768	DBusMessage *msg;
1769	DBusMessageIter iter;
1770	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1771	struct wpa_supplicant *parent;
1772
1773	iface = wpa_s->global->dbus;
1774
1775	/* Do nothing if the control interface is not turned on */
1776	if (iface == NULL)
1777		return;
1778
1779	if (!wpa_s->dbus_groupobj_path)
1780		return;
1781
1782	parent = wpa_s->parent;
1783	if (parent->p2p_mgmt)
1784		parent = parent->parent;
1785	if (!parent->dbus_new_path)
1786		return;
1787
1788	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1789			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1790			COMPACT_MACSTR,
1791			parent->dbus_new_path, MAC2STR(peer_addr));
1792
1793	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
1794				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
1795				      "PeerDisconnected");
1796	if (msg == NULL)
1797		return;
1798
1799	dbus_message_iter_init_append(msg, &iter);
1800	path = peer_obj_path;
1801	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
1802					    &path)) {
1803		wpa_printf(MSG_ERROR,
1804			   "dbus: Failed to construct PeerDisconnected signal");
1805	} else {
1806		dbus_connection_send(iface->con, msg, NULL);
1807		wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
1808	}
1809	dbus_message_unref(msg);
1810}
1811
1812
1813/**
1814 *
1815 * Method to emit a signal for a service discovery request.
1816 * The signal will carry station address, frequency, dialog token,
1817 * update indicator and it tlvs
1818 *
1819 * @wpa_s: %wpa_supplicant network interface data
1820 * @sa: station addr (p2p i/f) of the peer
1821 * @dialog_token: service discovery request dialog token
1822 * @update_indic: service discovery request update indicator
1823 * @tlvs: service discovery request genrated byte array of tlvs
1824 * @tlvs_len: service discovery request tlvs length
1825 */
1826void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
1827				     int freq, const u8 *sa, u8 dialog_token,
1828				     u16 update_indic, const u8 *tlvs,
1829				     size_t tlvs_len)
1830{
1831	DBusMessage *msg;
1832	DBusMessageIter iter, dict_iter;
1833	struct wpas_dbus_priv *iface;
1834	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1835
1836	iface = wpa_s->global->dbus;
1837
1838	/* Do nothing if the control interface is not turned on */
1839	if (iface == NULL)
1840		return;
1841
1842	if (wpa_s->p2p_mgmt)
1843		wpa_s = wpa_s->parent;
1844	if (!wpa_s->dbus_new_path)
1845		return;
1846
1847	/* Check if this is a known peer */
1848	if (!p2p_peer_known(wpa_s->global->p2p, sa))
1849		return;
1850
1851	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1852				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1853				      "ServiceDiscoveryRequest");
1854	if (msg == NULL)
1855		return;
1856
1857	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1858		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1859		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
1860
1861	path = peer_obj_path;
1862
1863	dbus_message_iter_init_append(msg, &iter);
1864	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1865	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
1866					      path) ||
1867	    !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
1868	    !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
1869					dialog_token) ||
1870	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
1871					 update_indic) ||
1872	    !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
1873					     (const char *) tlvs,
1874					     tlvs_len) ||
1875	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
1876		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1877	else
1878		dbus_connection_send(iface->con, msg, NULL);
1879	dbus_message_unref(msg);
1880}
1881
1882
1883/**
1884 *
1885 * Method to emit a signal for a service discovery response.
1886 * The signal will carry station address, update indicator and it
1887 * tlvs
1888 *
1889 * @wpa_s: %wpa_supplicant network interface data
1890 * @sa: station addr (p2p i/f) of the peer
1891 * @update_indic: service discovery request update indicator
1892 * @tlvs: service discovery request genrated byte array of tlvs
1893 * @tlvs_len: service discovery request tlvs length
1894 */
1895void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
1896				      const u8 *sa, u16 update_indic,
1897				      const u8 *tlvs, size_t tlvs_len)
1898{
1899	DBusMessage *msg;
1900	DBusMessageIter iter, dict_iter;
1901	struct wpas_dbus_priv *iface;
1902	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1903
1904	iface = wpa_s->global->dbus;
1905
1906	/* Do nothing if the control interface is not turned on */
1907	if (iface == NULL)
1908		return;
1909
1910	if (wpa_s->p2p_mgmt)
1911		wpa_s = wpa_s->parent;
1912	if (!wpa_s->dbus_new_path)
1913		return;
1914
1915	/* Check if this is a known peer */
1916	if (!p2p_peer_known(wpa_s->global->p2p, sa))
1917		return;
1918
1919	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1920				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1921				      "ServiceDiscoveryResponse");
1922	if (msg == NULL)
1923		return;
1924
1925	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1926		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1927		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
1928
1929	path = peer_obj_path;
1930
1931	dbus_message_iter_init_append(msg, &iter);
1932	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1933	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
1934					      path) ||
1935	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
1936					 update_indic) ||
1937	    !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
1938					     (const char *) tlvs,
1939					     tlvs_len) ||
1940	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
1941		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1942	else
1943		dbus_connection_send(iface->con, msg, NULL);
1944	dbus_message_unref(msg);
1945}
1946
1947
1948/**
1949 * wpas_dbus_signal_persistent_group - Send a persistent group related
1950 *	event signal
1951 * @wpa_s: %wpa_supplicant network interface data
1952 * @id: new persistent group id
1953 * @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved
1954 * @properties: determines if add second argument with object properties
1955 *
1956 * Notify listeners about an event related to persistent groups.
1957 */
1958static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
1959					      int id, const char *sig_name,
1960					      dbus_bool_t properties)
1961{
1962	struct wpas_dbus_priv *iface;
1963	DBusMessage *msg;
1964	DBusMessageIter iter;
1965	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1966
1967	iface = wpa_s->global->dbus;
1968
1969	/* Do nothing if the control interface is not turned on */
1970	if (iface == NULL)
1971		return;
1972
1973	if (wpa_s->p2p_mgmt)
1974		wpa_s = wpa_s->parent;
1975	if (!wpa_s->dbus_new_path)
1976		return;
1977
1978	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1979		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
1980		    wpa_s->dbus_new_path, id);
1981
1982	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1983				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1984				      sig_name);
1985	if (msg == NULL)
1986		return;
1987
1988	dbus_message_iter_init_append(msg, &iter);
1989	path = pgrp_obj_path;
1990	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
1991					    &path) ||
1992	    (properties &&
1993	     !wpa_dbus_get_object_properties(
1994		     iface, pgrp_obj_path,
1995		     WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter)))
1996		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1997	else
1998		dbus_connection_send(iface->con, msg, NULL);
1999
2000	dbus_message_unref(msg);
2001}
2002
2003
2004/**
2005 * wpas_dbus_signal_persistent_group_added - Send a persistent_group
2006 *	added signal
2007 * @wpa_s: %wpa_supplicant network interface data
2008 * @id: new persistent group id
2009 *
2010 * Notify listeners about addition of a new persistent group.
2011 */
2012static void wpas_dbus_signal_persistent_group_added(
2013	struct wpa_supplicant *wpa_s, int id)
2014{
2015	wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded",
2016					  TRUE);
2017}
2018
2019
2020/**
2021 * wpas_dbus_signal_persistent_group_removed - Send a persistent_group
2022 *	removed signal
2023 * @wpa_s: %wpa_supplicant network interface data
2024 * @id: persistent group id
2025 *
2026 * Notify listeners about removal of a persistent group.
2027 */
2028static void wpas_dbus_signal_persistent_group_removed(
2029	struct wpa_supplicant *wpa_s, int id)
2030{
2031	wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved",
2032					  FALSE);
2033}
2034
2035
2036/**
2037 * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event
2038 * @wpa_s: %wpa_supplicant network interface data
2039 * @fail: WPS failure information
2040 *
2041 * Sends Event dbus signal with name "fail" and dictionary containing
2042 * "msg" field with fail message number (int32) as arguments
2043 */
2044void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
2045				     struct wps_event_fail *fail)
2046{
2047
2048	DBusMessage *msg;
2049	DBusMessageIter iter, dict_iter;
2050	struct wpas_dbus_priv *iface;
2051	char *key = "fail";
2052
2053	iface = wpa_s->global->dbus;
2054
2055	/* Do nothing if the control interface is not turned on */
2056	if (iface == NULL)
2057		return;
2058
2059	if (wpa_s->p2p_mgmt)
2060		wpa_s = wpa_s->parent;
2061
2062	if (!wpa_s->dbus_new_path)
2063		return;
2064	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
2065				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2066				      "WpsFailed");
2067	if (msg == NULL)
2068		return;
2069
2070	dbus_message_iter_init_append(msg, &iter);
2071
2072	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
2073	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
2074	    !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
2075	    !wpa_dbus_dict_append_int16(&dict_iter, "config_error",
2076					fail->config_error) ||
2077	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
2078		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
2079	else
2080		dbus_connection_send(iface->con, msg, NULL);
2081
2082	dbus_message_unref(msg);
2083}
2084
2085
2086/**
2087 * wpas_dbus_signal_p2p_group_formation_failure - Signals GroupFormationFailure event
2088 * @wpa_s: %wpa_supplicant network interface data
2089 * @reason: indicates the reason code for group formation failure
2090 *
2091 * Sends Event dbus signal and string reason code when available.
2092 */
2093void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
2094						  const char *reason)
2095{
2096	DBusMessage *msg;
2097	struct wpas_dbus_priv *iface;
2098
2099	iface = wpa_s->global->dbus;
2100
2101	/* Do nothing if the control interface is not turned on */
2102	if (iface == NULL)
2103		return;
2104
2105	if (wpa_s->p2p_mgmt)
2106		wpa_s = wpa_s->parent;
2107
2108	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
2109				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2110				      "GroupFormationFailure");
2111	if (msg == NULL)
2112		return;
2113
2114	if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &reason,
2115				     DBUS_TYPE_INVALID))
2116		dbus_connection_send(iface->con, msg, NULL);
2117	else
2118		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
2119
2120	dbus_message_unref(msg);
2121}
2122
2123
2124/**
2125 * wpas_dbus_signal_p2p_invitation_received - Emit InvitationReceived signal
2126 * @wpa_s: %wpa_supplicant network interface data
2127 * @sa: Source address of the Invitation Request
2128 * @dev_add: GO Device Address
2129 * @bssid: P2P Group BSSID or %NULL if not received
2130 * @id: Persistent group id or %0 if not persistent group
2131 * @op_freq: Operating frequency for the group
2132 */
2133
2134void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s,
2135					      const u8 *sa, const u8 *dev_addr,
2136					      const u8 *bssid, int id,
2137					      int op_freq)
2138{
2139	DBusMessage *msg;
2140	DBusMessageIter iter, dict_iter;
2141	struct wpas_dbus_priv *iface;
2142
2143	iface = wpa_s->global->dbus;
2144
2145	/* Do nothing if the control interface is not turned on */
2146	if (iface == NULL)
2147		return;
2148
2149	if (wpa_s->p2p_mgmt)
2150		wpa_s = wpa_s->parent;
2151
2152	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
2153				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2154				      "InvitationReceived");
2155	if (msg == NULL)
2156		return;
2157
2158	dbus_message_iter_init_append(msg, &iter);
2159	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
2160	    (sa &&
2161	     !wpa_dbus_dict_append_byte_array(&dict_iter, "sa",
2162					      (const char *) sa, ETH_ALEN)) ||
2163	    (dev_addr &&
2164	     !wpa_dbus_dict_append_byte_array(&dict_iter, "go_dev_addr",
2165					      (const char *) dev_addr,
2166					      ETH_ALEN)) ||
2167	    (bssid &&
2168	     !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
2169					      (const char *) bssid,
2170					      ETH_ALEN)) ||
2171	    (id &&
2172	     !wpa_dbus_dict_append_int32(&dict_iter, "persistent_id", id)) ||
2173	    !wpa_dbus_dict_append_int32(&dict_iter, "op_freq", op_freq) ||
2174	    !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
2175		dbus_message_unref(msg);
2176		return;
2177	}
2178
2179	dbus_connection_send(iface->con, msg, NULL);
2180	dbus_message_unref(msg);
2181}
2182
2183
2184#endif /* CONFIG_P2P */
2185
2186
2187/**
2188 * wpas_dbus_signal_prop_changed - Signals change of property
2189 * @wpa_s: %wpa_supplicant network interface data
2190 * @property: indicates which property has changed
2191 *
2192 * Sends PropertyChanged signals with path, interface and arguments
2193 * depending on which property has changed.
2194 */
2195void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
2196				   enum wpas_dbus_prop property)
2197{
2198	char *prop;
2199	dbus_bool_t flush;
2200
2201	if (wpa_s->dbus_new_path == NULL)
2202		return; /* Skip signal since D-Bus setup is not yet ready */
2203
2204	flush = FALSE;
2205	switch (property) {
2206	case WPAS_DBUS_PROP_AP_SCAN:
2207		prop = "ApScan";
2208		break;
2209	case WPAS_DBUS_PROP_SCANNING:
2210		prop = "Scanning";
2211		break;
2212	case WPAS_DBUS_PROP_STATE:
2213		prop = "State";
2214		break;
2215	case WPAS_DBUS_PROP_CURRENT_BSS:
2216		prop = "CurrentBSS";
2217		break;
2218	case WPAS_DBUS_PROP_CURRENT_NETWORK:
2219		prop = "CurrentNetwork";
2220		break;
2221	case WPAS_DBUS_PROP_BSSS:
2222		prop = "BSSs";
2223		break;
2224	case WPAS_DBUS_PROP_STATIONS:
2225		prop = "Stations";
2226		break;
2227	case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
2228		prop = "CurrentAuthMode";
2229		break;
2230	case WPAS_DBUS_PROP_DISCONNECT_REASON:
2231		prop = "DisconnectReason";
2232		flush = TRUE;
2233		break;
2234	case WPAS_DBUS_PROP_AUTH_STATUS_CODE:
2235		prop = "AuthStatusCode";
2236		flush = TRUE;
2237		break;
2238	case WPAS_DBUS_PROP_ASSOC_STATUS_CODE:
2239		prop = "AssocStatusCode";
2240		flush = TRUE;
2241		break;
2242	case WPAS_DBUS_PROP_ROAM_TIME:
2243		prop = "RoamTime";
2244		break;
2245	case WPAS_DBUS_PROP_ROAM_COMPLETE:
2246		prop = "RoamComplete";
2247		break;
2248	case WPAS_DBUS_PROP_SESSION_LENGTH:
2249		prop = "SessionLength";
2250		break;
2251	case WPAS_DBUS_PROP_BSS_TM_STATUS:
2252		prop = "BSSTMStatus";
2253		break;
2254	default:
2255		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
2256			   __func__, property);
2257		return;
2258	}
2259
2260	wpa_dbus_mark_property_changed(wpa_s->global->dbus,
2261				       wpa_s->dbus_new_path,
2262				       WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
2263	if (flush) {
2264		wpa_dbus_flush_object_changed_properties(
2265			wpa_s->global->dbus->con, wpa_s->dbus_new_path);
2266	}
2267}
2268
2269
2270/**
2271 * wpas_dbus_bss_signal_prop_changed - Signals change of BSS property
2272 * @wpa_s: %wpa_supplicant network interface data
2273 * @property: indicates which property has changed
2274 * @id: unique BSS identifier
2275 *
2276 * Sends PropertyChanged signals with path, interface, and arguments depending
2277 * on which property has changed.
2278 */
2279void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
2280				       enum wpas_dbus_bss_prop property,
2281				       unsigned int id)
2282{
2283	char path[WPAS_DBUS_OBJECT_PATH_MAX];
2284	char *prop;
2285
2286	if (!wpa_s->dbus_new_path)
2287		return;
2288
2289	switch (property) {
2290	case WPAS_DBUS_BSS_PROP_SIGNAL:
2291		prop = "Signal";
2292		break;
2293	case WPAS_DBUS_BSS_PROP_FREQ:
2294		prop = "Frequency";
2295		break;
2296	case WPAS_DBUS_BSS_PROP_MODE:
2297		prop = "Mode";
2298		break;
2299	case WPAS_DBUS_BSS_PROP_PRIVACY:
2300		prop = "Privacy";
2301		break;
2302	case WPAS_DBUS_BSS_PROP_RATES:
2303		prop = "Rates";
2304		break;
2305	case WPAS_DBUS_BSS_PROP_WPA:
2306		prop = "WPA";
2307		break;
2308	case WPAS_DBUS_BSS_PROP_RSN:
2309		prop = "RSN";
2310		break;
2311	case WPAS_DBUS_BSS_PROP_WPS:
2312		prop = "WPS";
2313		break;
2314	case WPAS_DBUS_BSS_PROP_IES:
2315		prop = "IEs";
2316		break;
2317	case WPAS_DBUS_BSS_PROP_AGE:
2318		prop = "Age";
2319		break;
2320	default:
2321		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
2322			   __func__, property);
2323		return;
2324	}
2325
2326	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
2327		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
2328		    wpa_s->dbus_new_path, id);
2329
2330	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
2331				       WPAS_DBUS_NEW_IFACE_BSS, prop);
2332}
2333
2334
2335/**
2336 * wpas_dbus_sta_signal_prop_changed - Signals change of STA property
2337 * @wpa_s: %wpa_supplicant network interface data
2338 * @property: indicates which property has changed
2339 * @address: unique BSS identifier
2340 *
2341 * Sends PropertyChanged signals with path, interface, and arguments depending
2342 * on which property has changed.
2343 */
2344void wpas_dbus_sta_signal_prop_changed(struct wpa_supplicant *wpa_s,
2345				       enum wpas_dbus_bss_prop property,
2346				       u8 address[ETH_ALEN])
2347{
2348	char path[WPAS_DBUS_OBJECT_PATH_MAX];
2349	char *prop;
2350
2351	switch (property) {
2352	case WPAS_DBUS_STA_PROP_ADDRESS:
2353		prop = "Address";
2354		break;
2355	default:
2356		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
2357			   __func__, property);
2358		return;
2359	}
2360
2361	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
2362		    "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
2363		    wpa_s->dbus_new_path, MAC2STR(address));
2364
2365	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
2366				       WPAS_DBUS_NEW_IFACE_STA, prop);
2367}
2368
2369
2370/**
2371 * wpas_dbus_signal_debug_level_changed - Signals change of debug param
2372 * @global: wpa_global structure
2373 *
2374 * Sends PropertyChanged signals informing that debug level has changed.
2375 */
2376void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
2377{
2378	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
2379				       WPAS_DBUS_NEW_INTERFACE,
2380				       "DebugLevel");
2381}
2382
2383
2384/**
2385 * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
2386 * @global: wpa_global structure
2387 *
2388 * Sends PropertyChanged signals informing that debug timestamp has changed.
2389 */
2390void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
2391{
2392	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
2393				       WPAS_DBUS_NEW_INTERFACE,
2394				       "DebugTimestamp");
2395}
2396
2397
2398/**
2399 * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
2400 * @global: wpa_global structure
2401 *
2402 * Sends PropertyChanged signals informing that debug show_keys has changed.
2403 */
2404void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
2405{
2406	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
2407				       WPAS_DBUS_NEW_INTERFACE,
2408				       "DebugShowKeys");
2409}
2410
2411
2412static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc,
2413			       void *priv,
2414			       WPADBusArgumentFreeFunction priv_free,
2415			       const struct wpa_dbus_method_desc *methods,
2416			       const struct wpa_dbus_property_desc *properties,
2417			       const struct wpa_dbus_signal_desc *signals)
2418{
2419	int n;
2420
2421	obj_desc->user_data = priv;
2422	obj_desc->user_data_free_func = priv_free;
2423	obj_desc->methods = methods;
2424	obj_desc->properties = properties;
2425	obj_desc->signals = signals;
2426
2427	for (n = 0; properties && properties->dbus_property; properties++)
2428		n++;
2429
2430	obj_desc->prop_changed_flags = os_zalloc(n);
2431	if (!obj_desc->prop_changed_flags)
2432		wpa_printf(MSG_DEBUG, "dbus: %s: can't register handlers",
2433			   __func__);
2434}
2435
2436
2437static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
2438	{ "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
2439	  (WPADBusMethodHandler) wpas_dbus_handler_create_interface,
2440	  {
2441		  { "args", "a{sv}", ARG_IN },
2442		  { "path", "o", ARG_OUT },
2443		  END_ARGS
2444	  }
2445	},
2446	{ "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
2447	  (WPADBusMethodHandler) wpas_dbus_handler_remove_interface,
2448	  {
2449		  { "path", "o", ARG_IN },
2450		  END_ARGS
2451	  }
2452	},
2453	{ "GetInterface", WPAS_DBUS_NEW_INTERFACE,
2454	  (WPADBusMethodHandler) wpas_dbus_handler_get_interface,
2455	  {
2456		  { "ifname", "s", ARG_IN },
2457		  { "path", "o", ARG_OUT },
2458		  END_ARGS
2459	  }
2460	},
2461	{ "ExpectDisconnect", WPAS_DBUS_NEW_INTERFACE,
2462	  (WPADBusMethodHandler) wpas_dbus_handler_expect_disconnect,
2463	  {
2464		END_ARGS
2465	  }
2466	},
2467	{ NULL, NULL, NULL, { END_ARGS } }
2468};
2469
2470static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
2471	{ "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
2472	  wpas_dbus_getter_debug_level,
2473	  wpas_dbus_setter_debug_level,
2474	  NULL
2475	},
2476	{ "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
2477	  wpas_dbus_getter_debug_timestamp,
2478	  wpas_dbus_setter_debug_timestamp,
2479	  NULL
2480	},
2481	{ "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
2482	  wpas_dbus_getter_debug_show_keys,
2483	  wpas_dbus_setter_debug_show_keys,
2484	  NULL
2485	},
2486	{ "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
2487	  wpas_dbus_getter_interfaces,
2488	  NULL,
2489	  NULL
2490	},
2491	{ "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
2492	  wpas_dbus_getter_eap_methods,
2493	  NULL,
2494	  NULL
2495	},
2496	{ "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
2497	  wpas_dbus_getter_global_capabilities,
2498	  NULL,
2499	  NULL
2500	},
2501#ifdef CONFIG_WIFI_DISPLAY
2502	{ "WFDIEs", WPAS_DBUS_NEW_INTERFACE, "ay",
2503	  wpas_dbus_getter_global_wfd_ies,
2504	  wpas_dbus_setter_global_wfd_ies,
2505	  NULL
2506	},
2507#endif /* CONFIG_WIFI_DISPLAY */
2508	{ NULL, NULL, NULL, NULL, NULL, NULL }
2509};
2510
2511static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
2512	{ "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE,
2513	  {
2514		  { "path", "o", ARG_OUT },
2515		  { "properties", "a{sv}", ARG_OUT },
2516		  END_ARGS
2517	  }
2518	},
2519	{ "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE,
2520	  {
2521		  { "path", "o", ARG_OUT },
2522		  END_ARGS
2523	  }
2524	},
2525	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2526	{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
2527	  {
2528		  { "properties", "a{sv}", ARG_OUT },
2529		  END_ARGS
2530	  }
2531	},
2532	{ NULL, NULL, { END_ARGS } }
2533};
2534
2535
2536static char * uscore_to_dbus(const char *uscore)
2537{
2538	const char *p = uscore;
2539	char *str, *s;
2540	dbus_bool_t last_was_uscore = TRUE;
2541
2542	s = str = os_zalloc(os_strlen(uscore) + 1);
2543	if (!str)
2544		return NULL;
2545	while (p && *p) {
2546		if (*p == '_') {
2547			last_was_uscore = TRUE;
2548		} else {
2549			*s++ = last_was_uscore ? toupper(*p) : *p;
2550			last_was_uscore = FALSE;
2551		}
2552		p++;
2553	}
2554
2555	return str;
2556}
2557
2558
2559static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv);
2560
2561
2562static void wpa_dbus_ctrl_iface_props_deinit(struct wpas_dbus_priv *priv)
2563{
2564	int idx = priv->globals_start;
2565
2566	/* Free all allocated property values */
2567	while (priv->all_interface_properties[idx].dbus_property)
2568		os_free((char *)
2569			priv->all_interface_properties[idx++].dbus_property);
2570	os_free((char *) priv->all_interface_properties);
2571}
2572
2573
2574/**
2575 * wpas_dbus_ctrl_iface_init - Initialize dbus control interface
2576 * @global: Pointer to global data from wpa_supplicant_init()
2577 * Returns: 0 on success or -1 on failure
2578 *
2579 * Initialize the dbus control interface for wpa_supplicant and start
2580 * receiving commands from external programs over the bus.
2581 */
2582int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
2583{
2584	struct wpa_dbus_object_desc *obj_desc;
2585	int ret;
2586
2587	ret = wpa_dbus_ctrl_iface_props_init(priv);
2588	if (ret < 0) {
2589		wpa_printf(MSG_ERROR,
2590			   "dbus: Not enough memory to init interface properties");
2591		return -1;
2592	}
2593
2594	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
2595	if (!obj_desc) {
2596		wpa_printf(MSG_ERROR,
2597			   "Not enough memory to create object description");
2598		goto error;
2599	}
2600
2601	wpas_dbus_register(obj_desc, priv->global, NULL,
2602			   wpas_dbus_global_methods,
2603			   wpas_dbus_global_properties,
2604			   wpas_dbus_global_signals);
2605
2606	wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'",
2607		   WPAS_DBUS_NEW_PATH);
2608	ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
2609				       WPAS_DBUS_NEW_SERVICE,
2610				       obj_desc);
2611	if (ret < 0) {
2612		free_dbus_object_desc(obj_desc);
2613		goto error;
2614	}
2615
2616	priv->dbus_new_initialized = 1;
2617	return 0;
2618
2619error:
2620	wpa_dbus_ctrl_iface_props_deinit(priv);
2621	return -1;
2622}
2623
2624
2625/**
2626 * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
2627 * wpa_supplicant
2628 * @priv: Pointer to dbus private data from wpas_dbus_init()
2629 *
2630 * Deinitialize the dbus control interface that was initialized with
2631 * wpas_dbus_ctrl_iface_init().
2632 */
2633void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *priv)
2634{
2635	if (!priv->dbus_new_initialized)
2636		return;
2637	wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'",
2638		   WPAS_DBUS_NEW_PATH);
2639	dbus_connection_unregister_object_path(priv->con, WPAS_DBUS_NEW_PATH);
2640	wpa_dbus_ctrl_iface_props_deinit(priv);
2641}
2642
2643
2644static void wpa_dbus_free(void *ptr)
2645{
2646	os_free(ptr);
2647}
2648
2649
2650static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
2651	{ "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
2652	  wpas_dbus_getter_network_properties,
2653	  wpas_dbus_setter_network_properties,
2654	  NULL
2655	},
2656	{ "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
2657	  wpas_dbus_getter_enabled,
2658	  wpas_dbus_setter_enabled,
2659	  NULL
2660	},
2661	{ NULL, NULL, NULL, NULL, NULL, NULL }
2662};
2663
2664
2665static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = {
2666	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2667	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
2668	  {
2669		  { "properties", "a{sv}", ARG_OUT },
2670		  END_ARGS
2671	  }
2672	},
2673	{ NULL, NULL, { END_ARGS } }
2674};
2675
2676
2677/**
2678 * wpas_dbus_register_network - Register a configured network with dbus
2679 * @wpa_s: wpa_supplicant interface structure
2680 * @ssid: network configuration data
2681 * Returns: 0 on success, -1 on failure
2682 *
2683 * Registers network representing object with dbus
2684 */
2685int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
2686			       struct wpa_ssid *ssid)
2687{
2688	struct wpas_dbus_priv *ctrl_iface;
2689	struct wpa_dbus_object_desc *obj_desc;
2690	struct network_handler_args *arg;
2691	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2692
2693#ifdef CONFIG_P2P
2694	/*
2695	 * If it is a persistent group register it as such.
2696	 * This is to handle cases where an interface is being initialized
2697	 * with a list of networks read from config.
2698	 */
2699	if (network_is_persistent_group(ssid))
2700		return wpas_dbus_register_persistent_group(wpa_s, ssid);
2701#endif /* CONFIG_P2P */
2702
2703	/* Do nothing if the control interface is not turned on */
2704	if (wpa_s == NULL || wpa_s->global == NULL || !wpa_s->dbus_new_path)
2705		return 0;
2706	ctrl_iface = wpa_s->global->dbus;
2707	if (ctrl_iface == NULL)
2708		return 0;
2709
2710	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2711		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
2712		    wpa_s->dbus_new_path, ssid->id);
2713
2714	wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'",
2715		   net_obj_path);
2716	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
2717	if (!obj_desc) {
2718		wpa_printf(MSG_ERROR,
2719			   "Not enough memory to create object description");
2720		goto err;
2721	}
2722
2723	/* allocate memory for handlers arguments */
2724	arg = os_zalloc(sizeof(struct network_handler_args));
2725	if (!arg) {
2726		wpa_printf(MSG_ERROR,
2727			   "Not enough memory to create arguments for method");
2728		goto err;
2729	}
2730
2731	arg->wpa_s = wpa_s;
2732	arg->ssid = ssid;
2733
2734	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
2735			   wpas_dbus_network_properties,
2736			   wpas_dbus_network_signals);
2737
2738	if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path,
2739					       wpa_s->ifname, obj_desc))
2740		goto err;
2741
2742	wpas_dbus_signal_network_added(wpa_s, ssid->id);
2743
2744	return 0;
2745
2746err:
2747	free_dbus_object_desc(obj_desc);
2748	return -1;
2749}
2750
2751
2752/**
2753 * wpas_dbus_unregister_network - Unregister a configured network from dbus
2754 * @wpa_s: wpa_supplicant interface structure
2755 * @nid: network id
2756 * Returns: 0 on success, -1 on failure
2757 *
2758 * Unregisters network representing object from dbus
2759 */
2760int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
2761{
2762	struct wpas_dbus_priv *ctrl_iface;
2763	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2764	int ret;
2765#ifdef CONFIG_P2P
2766	struct wpa_ssid *ssid;
2767
2768	ssid = wpa_config_get_network(wpa_s->conf, nid);
2769
2770	/* If it is a persistent group unregister it as such */
2771	if (ssid && network_is_persistent_group(ssid))
2772		return wpas_dbus_unregister_persistent_group(wpa_s, nid);
2773#endif /* CONFIG_P2P */
2774
2775	/* Do nothing if the control interface is not turned on */
2776	if (wpa_s->global == NULL || wpa_s->dbus_new_path == NULL)
2777		return 0;
2778	ctrl_iface = wpa_s->global->dbus;
2779	if (ctrl_iface == NULL)
2780		return 0;
2781
2782	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2783		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
2784		    wpa_s->dbus_new_path, nid);
2785
2786	wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'",
2787		   net_obj_path);
2788	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path);
2789
2790	if (!ret)
2791		wpas_dbus_signal_network_removed(wpa_s, nid);
2792
2793	return ret;
2794}
2795
2796
2797static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
2798	{ "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
2799	  wpas_dbus_getter_bss_ssid,
2800	  NULL,
2801	  NULL
2802	},
2803	{ "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
2804	  wpas_dbus_getter_bss_bssid,
2805	  NULL,
2806	  NULL
2807	},
2808	{ "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
2809	  wpas_dbus_getter_bss_privacy,
2810	  NULL,
2811	  NULL
2812	},
2813	{ "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
2814	  wpas_dbus_getter_bss_mode,
2815	  NULL,
2816	  NULL
2817	},
2818	{ "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
2819	  wpas_dbus_getter_bss_signal,
2820	  NULL,
2821	  NULL
2822	},
2823	{ "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
2824	  wpas_dbus_getter_bss_frequency,
2825	  NULL,
2826	  NULL
2827	},
2828	{ "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
2829	  wpas_dbus_getter_bss_rates,
2830	  NULL,
2831	  NULL
2832	},
2833	{ "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
2834	  wpas_dbus_getter_bss_wpa,
2835	  NULL,
2836	  NULL
2837	},
2838	{ "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
2839	  wpas_dbus_getter_bss_rsn,
2840	  NULL,
2841	  NULL
2842	},
2843	{ "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
2844	  wpas_dbus_getter_bss_wps,
2845	  NULL,
2846	  NULL
2847	},
2848	{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
2849	  wpas_dbus_getter_bss_ies,
2850	  NULL,
2851	  NULL
2852	},
2853	{ "Age", WPAS_DBUS_NEW_IFACE_BSS, "u",
2854	  wpas_dbus_getter_bss_age,
2855	  NULL,
2856	  NULL
2857	},
2858	{
2859	  "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
2860	  wpas_dbus_getter_roam_time,
2861	  NULL,
2862	  NULL
2863	},
2864	{
2865	  "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
2866	  wpas_dbus_getter_roam_complete,
2867	  NULL,
2868	  NULL
2869	},
2870	{
2871	  "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
2872	  wpas_dbus_getter_session_length,
2873	  NULL,
2874	  NULL
2875	},
2876	{
2877	  "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
2878	  wpas_dbus_getter_bss_tm_status,
2879	  NULL,
2880	  NULL
2881	},
2882	{ NULL, NULL, NULL, NULL, NULL, NULL }
2883};
2884
2885
2886static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = {
2887	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2888	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS,
2889	  {
2890		  { "properties", "a{sv}", ARG_OUT },
2891		  END_ARGS
2892	  }
2893	},
2894	{ NULL, NULL, { END_ARGS } }
2895};
2896
2897
2898/**
2899 * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus
2900 * @wpa_s: wpa_supplicant interface structure
2901 * @bssid: scanned network bssid
2902 * @id: unique BSS identifier
2903 * Returns: 0 on success, -1 on failure
2904 *
2905 * Unregisters BSS representing object from dbus
2906 */
2907int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
2908			     u8 bssid[ETH_ALEN], unsigned int id)
2909{
2910	struct wpas_dbus_priv *ctrl_iface;
2911	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2912
2913	/* Do nothing if the control interface is not turned on */
2914	if (wpa_s == NULL || wpa_s->global == NULL || !wpa_s->dbus_new_path)
2915		return 0;
2916	ctrl_iface = wpa_s->global->dbus;
2917	if (ctrl_iface == NULL)
2918		return 0;
2919
2920	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2921		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
2922		    wpa_s->dbus_new_path, id);
2923
2924	wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'",
2925		   bss_obj_path);
2926	if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) {
2927		wpa_printf(MSG_ERROR, "dbus: Cannot unregister BSS object %s",
2928			   bss_obj_path);
2929		return -1;
2930	}
2931
2932	wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path);
2933	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
2934
2935	return 0;
2936}
2937
2938
2939/**
2940 * wpas_dbus_register_bss - Register a scanned BSS with dbus
2941 * @wpa_s: wpa_supplicant interface structure
2942 * @bssid: scanned network bssid
2943 * @id: unique BSS identifier
2944 * Returns: 0 on success, -1 on failure
2945 *
2946 * Registers BSS representing object with dbus
2947 */
2948int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
2949			   u8 bssid[ETH_ALEN], unsigned int id)
2950{
2951	struct wpas_dbus_priv *ctrl_iface;
2952	struct wpa_dbus_object_desc *obj_desc;
2953	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2954	struct bss_handler_args *arg;
2955
2956	/* Do nothing if the control interface is not turned on */
2957	if (wpa_s == NULL || wpa_s->global == NULL || !wpa_s->dbus_new_path)
2958		return 0;
2959	ctrl_iface = wpa_s->global->dbus;
2960	if (ctrl_iface == NULL)
2961		return 0;
2962
2963	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2964		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
2965		    wpa_s->dbus_new_path, id);
2966
2967	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
2968	if (!obj_desc) {
2969		wpa_printf(MSG_ERROR,
2970			   "Not enough memory to create object description");
2971		goto err;
2972	}
2973
2974	arg = os_zalloc(sizeof(struct bss_handler_args));
2975	if (!arg) {
2976		wpa_printf(MSG_ERROR,
2977			   "Not enough memory to create arguments for handler");
2978		goto err;
2979	}
2980	arg->wpa_s = wpa_s;
2981	arg->id = id;
2982
2983	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
2984			   wpas_dbus_bss_properties,
2985			   wpas_dbus_bss_signals);
2986
2987	wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'",
2988		   bss_obj_path);
2989	if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path,
2990					       wpa_s->ifname, obj_desc)) {
2991		wpa_printf(MSG_ERROR,
2992			   "Cannot register BSSID dbus object %s.",
2993			   bss_obj_path);
2994		goto err;
2995	}
2996
2997	wpas_dbus_signal_bss_added(wpa_s, bss_obj_path);
2998	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
2999
3000	return 0;
3001
3002err:
3003	free_dbus_object_desc(obj_desc);
3004	return -1;
3005}
3006
3007
3008static const struct wpa_dbus_property_desc wpas_dbus_sta_properties[] = {
3009	{ "Address", WPAS_DBUS_NEW_IFACE_STA, "ay",
3010	  wpas_dbus_getter_sta_address,
3011	  NULL, NULL
3012	},
3013	{ "AID", WPAS_DBUS_NEW_IFACE_STA, "q",
3014	  wpas_dbus_getter_sta_aid,
3015	  NULL, NULL
3016	},
3017	{ "Capabilities", WPAS_DBUS_NEW_IFACE_STA, "q",
3018	  wpas_dbus_getter_sta_caps,
3019	  NULL, NULL
3020	},
3021	{ "RxPackets", WPAS_DBUS_NEW_IFACE_STA, "t",
3022	  wpas_dbus_getter_sta_rx_packets,
3023	  NULL, NULL
3024	},
3025	{ "TxPackets", WPAS_DBUS_NEW_IFACE_STA, "t",
3026	  wpas_dbus_getter_sta_tx_packets,
3027	  NULL, NULL
3028	},
3029	{ "RxBytes", WPAS_DBUS_NEW_IFACE_STA, "t",
3030	  wpas_dbus_getter_sta_rx_bytes,
3031	  NULL, NULL
3032	},
3033	{ "TxBytes", WPAS_DBUS_NEW_IFACE_STA, "t",
3034	  wpas_dbus_getter_sta_tx_bytes,
3035	  NULL, NULL
3036	},
3037	{ NULL, NULL, NULL, NULL, NULL, NULL }
3038};
3039
3040
3041static const struct wpa_dbus_signal_desc wpas_dbus_sta_signals[] = {
3042	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
3043	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_STA,
3044	  {
3045		  { "properties", "a{sv}", ARG_OUT },
3046		  END_ARGS
3047	  }
3048	},
3049	{ NULL, NULL, { END_ARGS } }
3050};
3051
3052
3053/**
3054 * wpas_dbus_unregister_sta - Unregister a connected station from dbus
3055 * @wpa_s: wpa_supplicant interface structure
3056 * @sta: station MAC address
3057 * Returns: 0 on success, -1 on failure
3058 *
3059 * Unregisters STA representing object from dbus.
3060 */
3061int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, const u8 *sta)
3062{
3063	struct wpas_dbus_priv *ctrl_iface;
3064	char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3065
3066	/* Do nothing if the control interface is not turned on */
3067	if (!wpa_s || !wpa_s->global)
3068		return 0;
3069	ctrl_iface = wpa_s->global->dbus;
3070	if (!ctrl_iface)
3071		return 0;
3072
3073	os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3074		    "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
3075		    wpa_s->dbus_new_path, MAC2STR(sta));
3076
3077	wpa_printf(MSG_DEBUG, "dbus: Unregister STA object '%s'",
3078		   station_obj_path);
3079	if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
3080						 station_obj_path)) {
3081		wpa_printf(MSG_ERROR, "dbus: Cannot unregister STA object %s",
3082			   station_obj_path);
3083		return -1;
3084	}
3085
3086	wpas_dbus_signal_station_removed(wpa_s, station_obj_path);
3087	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS);
3088
3089	return 0;
3090}
3091
3092
3093/**
3094 * wpas_dbus_register_sta - Register a connected station with dbus
3095 * @wpa_s: wpa_supplicant interface structure
3096 * @sta: station MAC address
3097 * Returns: 0 on success, -1 on failure
3098 *
3099 * Registers STA representing object with dbus.
3100 */
3101int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, const u8 *sta)
3102{
3103	struct wpas_dbus_priv *ctrl_iface;
3104	struct wpa_dbus_object_desc *obj_desc;
3105	char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3106	struct sta_handler_args *arg;
3107
3108	/* Do nothing if the control interface is not turned on */
3109	if (!wpa_s || !wpa_s->global)
3110		return 0;
3111	ctrl_iface = wpa_s->global->dbus;
3112	if (!ctrl_iface)
3113		return 0;
3114
3115	os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3116		    "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
3117		    wpa_s->dbus_new_path, MAC2STR(sta));
3118
3119	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3120	if (!obj_desc) {
3121		wpa_printf(MSG_ERROR,
3122			   "Not enough memory to create object description");
3123		goto err;
3124	}
3125
3126	arg = os_zalloc(sizeof(struct sta_handler_args));
3127	if (!arg) {
3128		wpa_printf(MSG_ERROR,
3129			   "Not enough memory to create arguments for handler");
3130		goto err;
3131	}
3132	arg->wpa_s = wpa_s;
3133	arg->sta = sta;
3134
3135	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
3136			   wpas_dbus_sta_properties, wpas_dbus_sta_signals);
3137
3138	wpa_printf(MSG_DEBUG, "dbus: Register STA object '%s'",
3139		   station_obj_path);
3140	if (wpa_dbus_register_object_per_iface(ctrl_iface, station_obj_path,
3141					       wpa_s->ifname, obj_desc)) {
3142		wpa_printf(MSG_ERROR,
3143			   "Cannot register STA dbus object %s",
3144			   station_obj_path);
3145		goto err;
3146	}
3147
3148	wpas_dbus_signal_station_added(wpa_s, station_obj_path);
3149	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS);
3150
3151	return 0;
3152
3153err:
3154	free_dbus_object_desc(obj_desc);
3155	return -1;
3156}
3157
3158
3159static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
3160	{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
3161	  (WPADBusMethodHandler) wpas_dbus_handler_scan,
3162	  {
3163		  { "args", "a{sv}", ARG_IN },
3164		  END_ARGS
3165	  }
3166	},
3167	{ "SignalPoll", WPAS_DBUS_NEW_IFACE_INTERFACE,
3168	  (WPADBusMethodHandler) wpas_dbus_handler_signal_poll,
3169	  {
3170		  { "args", "a{sv}", ARG_OUT },
3171		  END_ARGS
3172	  }
3173	},
3174	{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
3175	  (WPADBusMethodHandler) wpas_dbus_handler_disconnect,
3176	  {
3177		  END_ARGS
3178	  }
3179	},
3180	{ "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
3181	  (WPADBusMethodHandler) wpas_dbus_handler_add_network,
3182	  {
3183		  { "args", "a{sv}", ARG_IN },
3184		  { "path", "o", ARG_OUT },
3185		  END_ARGS
3186	  }
3187	},
3188	{ "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
3189	  (WPADBusMethodHandler) wpas_dbus_handler_reassociate,
3190	  {
3191		  END_ARGS
3192	  }
3193	},
3194	{ "Reattach", WPAS_DBUS_NEW_IFACE_INTERFACE,
3195	  (WPADBusMethodHandler) wpas_dbus_handler_reattach,
3196	  {
3197		  END_ARGS
3198	  }
3199	},
3200	{ "Reconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
3201	  (WPADBusMethodHandler) wpas_dbus_handler_reconnect,
3202	  {
3203		  END_ARGS
3204	  }
3205	},
3206	{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
3207	  (WPADBusMethodHandler) wpas_dbus_handler_remove_network,
3208	  {
3209		  { "path", "o", ARG_IN },
3210		  END_ARGS
3211	  }
3212	},
3213	{ "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
3214	  (WPADBusMethodHandler) wpas_dbus_handler_remove_all_networks,
3215	  {
3216		  END_ARGS
3217	  }
3218	},
3219	{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
3220	  (WPADBusMethodHandler) wpas_dbus_handler_select_network,
3221	  {
3222		  { "path", "o", ARG_IN },
3223		  END_ARGS
3224	  }
3225	},
3226	{ "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
3227	  (WPADBusMethodHandler) wpas_dbus_handler_network_reply,
3228	  {
3229		  { "path", "o", ARG_IN },
3230		  { "field", "s", ARG_IN },
3231		  { "value", "s", ARG_IN },
3232		  END_ARGS
3233	  }
3234	},
3235#ifndef CONFIG_NO_CONFIG_BLOBS
3236	{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
3237	  (WPADBusMethodHandler) wpas_dbus_handler_add_blob,
3238	  {
3239		  { "name", "s", ARG_IN },
3240		  { "data", "ay", ARG_IN },
3241		  END_ARGS
3242	  }
3243	},
3244	{ "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
3245	  (WPADBusMethodHandler) wpas_dbus_handler_get_blob,
3246	  {
3247		  { "name", "s", ARG_IN },
3248		  { "data", "ay", ARG_OUT },
3249		  END_ARGS
3250	  }
3251	},
3252	{ "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
3253	  (WPADBusMethodHandler) wpas_dbus_handler_remove_blob,
3254	  {
3255		  { "name", "s", ARG_IN },
3256		  END_ARGS
3257	  }
3258	},
3259#endif /* CONFIG_NO_CONFIG_BLOBS */
3260	{ "SetPKCS11EngineAndModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE,
3261	  (WPADBusMethodHandler)
3262	  wpas_dbus_handler_set_pkcs11_engine_and_module_path,
3263	  {
3264		  { "pkcs11_engine_path", "s", ARG_IN },
3265		  { "pkcs11_module_path", "s", ARG_IN },
3266		  END_ARGS
3267	  }
3268	},
3269#ifdef CONFIG_WPS
3270	{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
3271	  (WPADBusMethodHandler) wpas_dbus_handler_wps_start,
3272	  {
3273		  { "args", "a{sv}", ARG_IN },
3274		  { "output", "a{sv}", ARG_OUT },
3275		  END_ARGS
3276	  }
3277	},
3278	{ "Cancel", WPAS_DBUS_NEW_IFACE_WPS,
3279	  (WPADBusMethodHandler) wpas_dbus_handler_wps_cancel,
3280	  {
3281		  END_ARGS
3282	  }
3283	},
3284#endif /* CONFIG_WPS */
3285#ifdef CONFIG_P2P
3286	{ "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3287	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_find,
3288	  {
3289		  { "args", "a{sv}", ARG_IN },
3290		  END_ARGS
3291	  }
3292	},
3293	{ "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3294	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_stop_find,
3295	  {
3296		  END_ARGS
3297	  }
3298	},
3299	{ "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3300	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_listen,
3301	  {
3302		  { "timeout", "i", ARG_IN },
3303		  END_ARGS
3304	  }
3305	},
3306	{ "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3307	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_extendedlisten,
3308	  {
3309		  { "args", "a{sv}", ARG_IN },
3310		  END_ARGS
3311	  }
3312	},
3313	{ "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3314	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_presence_request,
3315	  {
3316		  { "args", "a{sv}", ARG_IN },
3317		  END_ARGS
3318	  }
3319	},
3320	{ "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3321	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_prov_disc_req,
3322	  {
3323		  { "peer", "o", ARG_IN },
3324		  { "config_method", "s", ARG_IN },
3325		  END_ARGS
3326	  }
3327	},
3328	{ "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3329	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_connect,
3330	  {
3331		  { "args", "a{sv}", ARG_IN },
3332		  { "generated_pin", "s", ARG_OUT },
3333		  END_ARGS
3334	  }
3335	},
3336	{ "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3337	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_group_add,
3338	  {
3339		  { "args", "a{sv}", ARG_IN },
3340		  END_ARGS
3341	  }
3342	},
3343	{ "Cancel", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3344	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_cancel,
3345	  {
3346		  END_ARGS
3347	  }
3348	},
3349	{ "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3350	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_invite,
3351	  {
3352		  { "args", "a{sv}", ARG_IN },
3353		  END_ARGS
3354	  }
3355	},
3356	{ "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3357	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_disconnect,
3358	  {
3359		  END_ARGS
3360	  }
3361	},
3362	{ "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3363	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_rejectpeer,
3364	  {
3365		  { "peer", "o", ARG_IN },
3366		  END_ARGS
3367	  }
3368	},
3369	{ "RemoveClient", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3370	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_remove_client,
3371	  {
3372		  { "args", "a{sv}", ARG_IN },
3373		  END_ARGS
3374	  }
3375	},
3376	{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3377	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush,
3378	  {
3379		  END_ARGS
3380	  }
3381	},
3382	{ "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3383	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_add_service,
3384	  {
3385		  { "args", "a{sv}", ARG_IN },
3386		  END_ARGS
3387	  }
3388	},
3389	{ "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3390	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_delete_service,
3391	  {
3392		  { "args", "a{sv}", ARG_IN },
3393		  END_ARGS
3394	  }
3395	},
3396	{ "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3397	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush_service,
3398	  {
3399		  END_ARGS
3400	  }
3401	},
3402	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3403	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_req,
3404	  {
3405		  { "args", "a{sv}", ARG_IN },
3406		  { "ref", "t", ARG_OUT },
3407		  END_ARGS
3408	  }
3409	},
3410	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3411	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_res,
3412	  {
3413		  { "args", "a{sv}", ARG_IN },
3414		  END_ARGS
3415	  }
3416	},
3417	{ "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3418	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_cancel_req,
3419	  {
3420		  { "args", "t", ARG_IN },
3421		  END_ARGS
3422	  }
3423	},
3424	{ "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3425	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_update,
3426	  {
3427		  END_ARGS
3428	  }
3429	},
3430	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3431	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_serv_disc_external,
3432	  {
3433		  { "arg", "i", ARG_IN },
3434		  END_ARGS
3435	  }
3436	},
3437	{ "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3438	  (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group,
3439	  {
3440		  { "args", "a{sv}", ARG_IN },
3441		  { "path", "o", ARG_OUT },
3442		  END_ARGS
3443	  }
3444	},
3445	{ "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3446	  (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group,
3447	  {
3448		  { "path", "o", ARG_IN },
3449		  END_ARGS
3450	  }
3451	},
3452	{ "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3453	  (WPADBusMethodHandler)
3454	  wpas_dbus_handler_remove_all_persistent_groups,
3455	  {
3456		  END_ARGS
3457	  }
3458	},
3459#endif /* CONFIG_P2P */
3460	{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
3461	  (WPADBusMethodHandler) wpas_dbus_handler_flush_bss,
3462	  {
3463		  { "age", "u", ARG_IN },
3464		  END_ARGS
3465	  }
3466	},
3467#ifdef CONFIG_AP
3468	{ "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
3469	  (WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq,
3470	  {
3471		  END_ARGS
3472	  }
3473	},
3474	{ "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
3475	  (WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq,
3476	  {
3477		  END_ARGS
3478	  }
3479	},
3480#endif /* CONFIG_AP */
3481	{ "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE,
3482	  (WPADBusMethodHandler) wpas_dbus_handler_eap_logoff,
3483	  {
3484		  END_ARGS
3485	  }
3486	},
3487	{ "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE,
3488	  (WPADBusMethodHandler) wpas_dbus_handler_eap_logon,
3489	  {
3490		  END_ARGS
3491	  }
3492	},
3493#ifdef CONFIG_AUTOSCAN
3494	{ "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
3495	  (WPADBusMethodHandler) wpas_dbus_handler_autoscan,
3496	  {
3497		  { "arg", "s", ARG_IN },
3498		  END_ARGS
3499	  }
3500	},
3501#endif /* CONFIG_AUTOSCAN */
3502#ifdef CONFIG_TDLS
3503	{ "TDLSDiscover", WPAS_DBUS_NEW_IFACE_INTERFACE,
3504	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_discover,
3505	  {
3506		  { "peer_address", "s", ARG_IN },
3507		  END_ARGS
3508	  }
3509	},
3510	{ "TDLSSetup", WPAS_DBUS_NEW_IFACE_INTERFACE,
3511	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_setup,
3512	  {
3513		  { "peer_address", "s", ARG_IN },
3514		  END_ARGS
3515	  }
3516	},
3517	{ "TDLSStatus", WPAS_DBUS_NEW_IFACE_INTERFACE,
3518	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_status,
3519	  {
3520		  { "peer_address", "s", ARG_IN },
3521		  { "status", "s", ARG_OUT },
3522		  END_ARGS
3523	  }
3524	},
3525	{ "TDLSTeardown", WPAS_DBUS_NEW_IFACE_INTERFACE,
3526	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_teardown,
3527	  {
3528		  { "peer_address", "s", ARG_IN },
3529		  END_ARGS
3530	  }
3531	},
3532	{ "TDLSChannelSwitch", WPAS_DBUS_NEW_IFACE_INTERFACE,
3533	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_channel_switch,
3534	  {
3535		  { "args", "a{sv}", ARG_IN },
3536		  END_ARGS
3537	  }
3538	},
3539	{ "TDLSCancelChannelSwitch", WPAS_DBUS_NEW_IFACE_INTERFACE,
3540	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_cancel_channel_switch,
3541	  {
3542		  { "peer_address", "s", ARG_IN },
3543		  END_ARGS
3544	  }
3545	},
3546#endif /* CONFIG_TDLS */
3547	{ "VendorElemAdd", WPAS_DBUS_NEW_IFACE_INTERFACE,
3548	  (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_add,
3549	  {
3550		  { "frame_id", "i", ARG_IN },
3551		  { "ielems", "ay", ARG_IN },
3552		  END_ARGS
3553	  }
3554	},
3555	{ "VendorElemGet", WPAS_DBUS_NEW_IFACE_INTERFACE,
3556	  (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_get,
3557	  {
3558		  { "frame_id", "i", ARG_IN },
3559		  { "ielems", "ay", ARG_OUT },
3560		  END_ARGS
3561	  }
3562	},
3563	{ "VendorElemRem", WPAS_DBUS_NEW_IFACE_INTERFACE,
3564	  (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_remove,
3565	  {
3566		  { "frame_id", "i", ARG_IN },
3567		  { "ielems", "ay", ARG_IN },
3568		  END_ARGS
3569	  }
3570	},
3571#ifndef CONFIG_NO_CONFIG_WRITE
3572	{ "SaveConfig", WPAS_DBUS_NEW_IFACE_INTERFACE,
3573	  (WPADBusMethodHandler) wpas_dbus_handler_save_config,
3574	  {
3575		  END_ARGS
3576	  }
3577	},
3578#endif /* CONFIG_NO_CONFIG_WRITE */
3579	{ "AbortScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
3580	  (WPADBusMethodHandler) wpas_dbus_handler_abort_scan,
3581	  {
3582		  END_ARGS
3583	  }
3584	},
3585	{ NULL, NULL, NULL, { END_ARGS } }
3586};
3587
3588static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
3589	{ "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
3590	  wpas_dbus_getter_capabilities,
3591	  NULL,
3592	  NULL
3593	},
3594	{ "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
3595	  wpas_dbus_getter_state,
3596	  NULL,
3597	  NULL
3598	},
3599	{ "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
3600	  wpas_dbus_getter_scanning,
3601	  NULL,
3602	  NULL
3603	},
3604	{ "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
3605	  wpas_dbus_getter_ap_scan,
3606	  wpas_dbus_setter_ap_scan,
3607	  NULL
3608	},
3609	{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
3610	  wpas_dbus_getter_bss_expire_age,
3611	  wpas_dbus_setter_bss_expire_age,
3612	  NULL
3613	},
3614	{ "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
3615	  wpas_dbus_getter_bss_expire_count,
3616	  wpas_dbus_setter_bss_expire_count,
3617	  NULL
3618	},
3619	{ "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
3620	  wpas_dbus_getter_country,
3621	  wpas_dbus_setter_country,
3622	  NULL
3623	},
3624	{ "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
3625	  wpas_dbus_getter_ifname,
3626	  NULL,
3627	  NULL
3628	},
3629	{ "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
3630	  wpas_dbus_getter_driver,
3631	  NULL,
3632	  NULL
3633	},
3634	{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
3635	  wpas_dbus_getter_bridge_ifname,
3636	  NULL,
3637	  NULL
3638	},
3639	{ "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
3640	  wpas_dbus_getter_config_file,
3641	  NULL,
3642	  NULL
3643	},
3644	{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
3645	  wpas_dbus_getter_current_bss,
3646	  NULL,
3647	  NULL
3648	},
3649	{ "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
3650	  wpas_dbus_getter_current_network,
3651	  NULL,
3652	  NULL
3653	},
3654	{ "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
3655	  wpas_dbus_getter_current_auth_mode,
3656	  NULL,
3657	  NULL
3658	},
3659	{ "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
3660	  wpas_dbus_getter_blobs,
3661	  NULL,
3662	  NULL
3663	},
3664	{ "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
3665	  wpas_dbus_getter_bsss,
3666	  NULL,
3667	  NULL
3668	},
3669	{ "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
3670	  wpas_dbus_getter_networks,
3671	  NULL,
3672	  NULL
3673	},
3674	{ "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
3675	  wpas_dbus_getter_fast_reauth,
3676	  wpas_dbus_setter_fast_reauth,
3677	  NULL
3678	},
3679	{ "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
3680	  wpas_dbus_getter_scan_interval,
3681	  wpas_dbus_setter_scan_interval,
3682	  NULL
3683	},
3684	{ "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
3685	  wpas_dbus_getter_pkcs11_engine_path,
3686	  NULL,
3687	  NULL
3688	},
3689	{ "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
3690	  wpas_dbus_getter_pkcs11_module_path,
3691	  NULL,
3692	  NULL
3693	},
3694#ifdef CONFIG_WPS
3695	{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
3696	  wpas_dbus_getter_process_credentials,
3697	  wpas_dbus_setter_process_credentials,
3698	  NULL
3699	},
3700	{ "ConfigMethods", WPAS_DBUS_NEW_IFACE_WPS, "s",
3701	  wpas_dbus_getter_config_methods,
3702	  wpas_dbus_setter_config_methods,
3703	  NULL
3704	},
3705	{
3706	  "DeviceName", WPAS_DBUS_NEW_IFACE_WPS, "s",
3707	  wpas_dbus_getter_wps_device_name,
3708	  wpas_dbus_setter_wps_device_name,
3709	  NULL
3710	},
3711	{
3712	  "Manufacturer", WPAS_DBUS_NEW_IFACE_WPS, "s",
3713	  wpas_dbus_getter_wps_manufacturer,
3714	  wpas_dbus_setter_wps_manufacturer,
3715	  NULL
3716	},
3717	{
3718	  "ModelName", WPAS_DBUS_NEW_IFACE_WPS, "s",
3719	  wpas_dbus_getter_wps_device_model_name,
3720	  wpas_dbus_setter_wps_device_model_name,
3721	  NULL
3722	},
3723	{
3724	  "ModelNumber", WPAS_DBUS_NEW_IFACE_WPS, "s",
3725	  wpas_dbus_getter_wps_device_model_number,
3726	  wpas_dbus_setter_wps_device_model_number,
3727	  NULL
3728	},
3729	{
3730	  "SerialNumber", WPAS_DBUS_NEW_IFACE_WPS, "s",
3731	  wpas_dbus_getter_wps_device_serial_number,
3732	  wpas_dbus_setter_wps_device_serial_number,
3733	  NULL
3734	},
3735	{
3736	  "DeviceType", WPAS_DBUS_NEW_IFACE_WPS, "ay",
3737	  wpas_dbus_getter_wps_device_device_type,
3738	  wpas_dbus_setter_wps_device_device_type,
3739	  NULL
3740	},
3741#endif /* CONFIG_WPS */
3742#ifdef CONFIG_P2P
3743	{ "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
3744	  wpas_dbus_getter_p2p_device_config,
3745	  wpas_dbus_setter_p2p_device_config,
3746	  NULL
3747	},
3748	{ "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
3749	  wpas_dbus_getter_p2p_peers,
3750	  NULL,
3751	  NULL
3752	},
3753	{ "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
3754	  wpas_dbus_getter_p2p_role,
3755	  NULL,
3756	  NULL
3757	},
3758	{ "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
3759	  wpas_dbus_getter_p2p_group,
3760	  NULL,
3761	  NULL
3762	},
3763	{ "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
3764	  wpas_dbus_getter_p2p_peergo,
3765	  NULL,
3766	  NULL
3767	},
3768	{ "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
3769	  wpas_dbus_getter_persistent_groups,
3770	  NULL,
3771	  NULL
3772	},
3773#endif /* CONFIG_P2P */
3774	{ "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
3775	  wpas_dbus_getter_disconnect_reason,
3776	  NULL,
3777	  NULL
3778	},
3779	{ "AuthStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
3780	  wpas_dbus_getter_auth_status_code,
3781	  NULL,
3782	  NULL
3783	},
3784	{ "AssocStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
3785	  wpas_dbus_getter_assoc_status_code,
3786	  NULL,
3787	  NULL
3788	},
3789#ifdef CONFIG_MESH
3790	{ "MeshPeers", WPAS_DBUS_NEW_IFACE_MESH, "aay",
3791	  wpas_dbus_getter_mesh_peers,
3792	  NULL,
3793	  NULL
3794	},
3795	{ "MeshGroup", WPAS_DBUS_NEW_IFACE_MESH, "ay",
3796	  wpas_dbus_getter_mesh_group,
3797	  NULL,
3798	  NULL
3799	},
3800#endif /* CONFIG_MESH */
3801	{ "Stations", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
3802	  wpas_dbus_getter_stas,
3803	  NULL,
3804	  NULL
3805	},
3806	{ NULL, NULL, NULL, NULL, NULL, NULL }
3807};
3808
3809static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
3810	{ "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
3811	  {
3812		  { "success", "b", ARG_OUT },
3813		  END_ARGS
3814	  }
3815	},
3816	{ "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
3817	  {
3818		  { "path", "o", ARG_OUT },
3819		  { "properties", "a{sv}", ARG_OUT },
3820		  END_ARGS
3821	  }
3822	},
3823	{ "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
3824	  {
3825		  { "path", "o", ARG_OUT },
3826		  END_ARGS
3827	  }
3828	},
3829	{ "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
3830	  {
3831		  { "name", "s", ARG_OUT },
3832		  END_ARGS
3833	  }
3834	},
3835	{ "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
3836	  {
3837		  { "name", "s", ARG_OUT },
3838		  END_ARGS
3839	  }
3840	},
3841	{ "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
3842	  {
3843		  { "path", "o", ARG_OUT },
3844		  { "properties", "a{sv}", ARG_OUT },
3845		  END_ARGS
3846	  }
3847	},
3848	{ "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
3849	  {
3850		  { "path", "o", ARG_OUT },
3851		  END_ARGS
3852	  }
3853	},
3854	{ "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE,
3855	  {
3856		  { "path", "o", ARG_OUT },
3857		  END_ARGS
3858	  }
3859	},
3860	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
3861	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
3862	  {
3863		  { "properties", "a{sv}", ARG_OUT },
3864		  END_ARGS
3865	  }
3866	},
3867#ifdef CONFIG_WPS
3868	{ "Event", WPAS_DBUS_NEW_IFACE_WPS,
3869	  {
3870		  { "name", "s", ARG_OUT },
3871		  { "args", "a{sv}", ARG_OUT },
3872		  END_ARGS
3873	  }
3874	},
3875	{ "Credentials", WPAS_DBUS_NEW_IFACE_WPS,
3876	  {
3877		  { "credentials", "a{sv}", ARG_OUT },
3878		  END_ARGS
3879	  }
3880	},
3881	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
3882	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
3883	  {
3884		  { "properties", "a{sv}", ARG_OUT },
3885		  END_ARGS
3886	  }
3887	},
3888#endif /* CONFIG_WPS */
3889#ifdef CONFIG_P2P
3890	{ "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3891	  {
3892		  { "path", "o", ARG_OUT },
3893		  END_ARGS
3894	  }
3895	},
3896	{ "DeviceFoundProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3897	  {
3898		  { "path", "o", ARG_OUT },
3899		  { "properties", "a{sv}", ARG_OUT },
3900		  END_ARGS
3901	  }
3902	},
3903	{ "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3904	  {
3905		  { "path", "o", ARG_OUT },
3906		  END_ARGS
3907	  }
3908	},
3909	{ "FindStopped", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3910	  {
3911		  END_ARGS
3912	  }
3913	},
3914	{ "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3915	  {
3916		  { "peer_object", "o", ARG_OUT },
3917		  { "pin", "s", ARG_OUT },
3918		  END_ARGS
3919	  }
3920	},
3921	{ "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3922	  {
3923		  { "peer_object", "o", ARG_OUT },
3924		  { "pin", "s", ARG_OUT },
3925		  END_ARGS
3926	  }
3927	},
3928	{ "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3929	  {
3930		  { "peer_object", "o", ARG_OUT },
3931		  END_ARGS
3932	  }
3933	},
3934	{ "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3935	  {
3936		  { "peer_object", "o", ARG_OUT },
3937		  END_ARGS
3938	  }
3939	},
3940	{ "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3941	  {
3942		  { "peer_object", "o", ARG_OUT },
3943		  END_ARGS
3944	  }
3945	},
3946	{ "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3947	  {
3948		  { "peer_object", "o", ARG_OUT },
3949		  END_ARGS
3950	  }
3951	},
3952	{ "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3953	  {
3954		  { "peer_object", "o", ARG_OUT },
3955		  { "status", "i", ARG_OUT },
3956		  END_ARGS
3957	  }
3958	},
3959	{ "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3960	  {
3961		  { "properties", "a{sv}", ARG_OUT },
3962		  END_ARGS
3963	  }
3964	},
3965	{ "GroupFormationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3966	  {
3967		  { "reason", "s", ARG_OUT },
3968		  END_ARGS
3969	  }
3970	},
3971	{ "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3972	  {
3973		  { "properties", "a{sv}", ARG_OUT },
3974		  END_ARGS
3975	  }
3976	},
3977	{ "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3978	  {
3979		  { "properties", "a{sv}", ARG_OUT },
3980		  END_ARGS
3981	  }
3982	},
3983	{ "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3984	  {
3985		  { "path", "o", ARG_OUT },
3986		  { "dev_passwd_id", "q", ARG_OUT },
3987		  { "device_go_intent", "y", ARG_OUT },
3988		  END_ARGS
3989	  }
3990	},
3991	{ "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3992	  {
3993		  { "invite_result", "a{sv}", ARG_OUT },
3994		  END_ARGS
3995	  }
3996	},
3997	{ "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3998	  {
3999		  { "properties", "a{sv}", ARG_OUT },
4000		  END_ARGS
4001	  }
4002	},
4003	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4004	  {
4005		  { "sd_request", "a{sv}", ARG_OUT },
4006		  END_ARGS
4007	  }
4008	},
4009	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4010	  {
4011		  { "sd_response", "a{sv}", ARG_OUT },
4012		  END_ARGS
4013	  }
4014	},
4015	{ "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4016	  {
4017		  { "path", "o", ARG_OUT },
4018		  { "properties", "a{sv}", ARG_OUT },
4019		  END_ARGS
4020	  }
4021	},
4022	{ "PersistentGroupRemoved", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4023	  {
4024		  { "path", "o", ARG_OUT },
4025		  END_ARGS
4026	  }
4027	},
4028	{ "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4029	  {
4030		  { "name", "s", ARG_OUT },
4031		  { "args", "a{sv}", ARG_OUT },
4032		  END_ARGS
4033	  }
4034	},
4035	{ "InvitationReceived", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4036	  {
4037		  { "properties", "a{sv}", ARG_OUT },
4038		  END_ARGS
4039	  }
4040	},
4041#endif /* CONFIG_P2P */
4042#ifdef CONFIG_AP
4043	{ "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
4044	  {
4045		  { "args", "a{sv}", ARG_OUT },
4046		  END_ARGS
4047	  }
4048	},
4049#endif /* CONFIG_AP */
4050	{ "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
4051	  {
4052		  { "certification", "a{sv}", ARG_OUT },
4053		  END_ARGS
4054	  }
4055	},
4056	{ "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE,
4057	  {
4058		  { "status", "s", ARG_OUT },
4059		  { "parameter", "s", ARG_OUT },
4060		  END_ARGS
4061	  }
4062	},
4063	{ "StaAuthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
4064	  {
4065		  { "name", "s", ARG_OUT },
4066		  END_ARGS
4067	  }
4068	},
4069	{ "StaDeauthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
4070	  {
4071		  { "name", "s", ARG_OUT },
4072		  END_ARGS
4073	  }
4074	},
4075	{ "StationAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
4076	  {
4077		  { "path", "o", ARG_OUT },
4078		  { "properties", "a{sv}", ARG_OUT },
4079		  END_ARGS
4080	  }
4081	},
4082	{ "StationRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
4083	  {
4084		  { "path", "o", ARG_OUT },
4085		  END_ARGS
4086	  }
4087	},
4088	{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
4089	  {
4090		  { "path", "o", ARG_OUT },
4091		  { "field", "s", ARG_OUT },
4092		  { "text", "s", ARG_OUT },
4093		  END_ARGS
4094	  }
4095	},
4096#ifdef CONFIG_MESH
4097	{ "MeshGroupStarted", WPAS_DBUS_NEW_IFACE_MESH,
4098	  {
4099		  { "args", "a{sv}", ARG_OUT },
4100		  END_ARGS
4101	  }
4102	},
4103	{ "MeshGroupRemoved", WPAS_DBUS_NEW_IFACE_MESH,
4104	  {
4105		  { "args", "a{sv}", ARG_OUT },
4106		  END_ARGS
4107	  }
4108	},
4109	{ "MeshPeerConnected", WPAS_DBUS_NEW_IFACE_MESH,
4110	  {
4111		  { "args", "a{sv}", ARG_OUT },
4112		  END_ARGS
4113	  }
4114	},
4115	{ "MeshPeerDisconnected", WPAS_DBUS_NEW_IFACE_MESH,
4116	  {
4117		  { "args", "a{sv}", ARG_OUT },
4118		  END_ARGS
4119	  }
4120	},
4121#endif /* CONFIG_MESH */
4122	{ NULL, NULL, { END_ARGS } }
4123};
4124
4125
4126static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv)
4127{
4128	size_t all_size;
4129	unsigned int i, j, count, num_const, num_globals;
4130	const char *global_name;
4131	static const char * const ignored_globals[] = {
4132		"bss_expiration_age", "bss_expiration_scan_count",
4133		"ap_scan", "country", "fast_reauth",
4134		"pkcs11_engine_path", "pkcs11_module_path"
4135	};
4136
4137	/* wpas_dbus_interface_properties terminates with a NULL element */
4138	num_const = ARRAY_SIZE(wpas_dbus_interface_properties) - 1;
4139
4140	num_globals = wpa_config_get_num_global_field_names();
4141	priv->globals_start = num_const;
4142
4143	/* allocate enough for all properties + terminating NULL element */
4144	all_size = (num_globals + num_const + 1) *
4145		sizeof(wpas_dbus_interface_properties[0]);
4146	priv->all_interface_properties = os_zalloc(all_size);
4147	if (!priv->all_interface_properties) {
4148		wpa_printf(MSG_ERROR,
4149			   "dbus: Not enough memory for interface properties");
4150		return -1;
4151	}
4152
4153	/* Copy constant interface properties to the start of the array */
4154	os_memcpy(priv->all_interface_properties,
4155		  wpas_dbus_interface_properties,
4156		  sizeof(wpas_dbus_interface_properties));
4157
4158	/* Dynamically construct interface global properties */
4159	for (i = 0, count = num_const; i < num_globals; i++) {
4160		struct wpa_dbus_property_desc *desc;
4161		int no_var = 0;
4162
4163		/* ignore globals that are actually just methods */
4164		global_name = wpa_config_get_global_field_name(i, &no_var);
4165		if (no_var)
4166			continue;
4167		/* Ignore fields already explicitly exposed */
4168		for (j = 0; j < ARRAY_SIZE(ignored_globals); j++) {
4169			if (os_strcmp(global_name, ignored_globals[j]) == 0)
4170				break;
4171		}
4172		if (j < ARRAY_SIZE(ignored_globals))
4173			continue;
4174
4175		desc = &priv->all_interface_properties[count++];
4176		desc->dbus_property = uscore_to_dbus(global_name);
4177		if (!desc->dbus_property) {
4178			wpa_printf(MSG_ERROR,
4179				   "dbus: Not enough memory for D-Bus property name");
4180			goto error;
4181		}
4182		desc->dbus_interface = WPAS_DBUS_NEW_IFACE_INTERFACE;
4183		desc->type = "s";
4184		desc->getter = wpas_dbus_getter_iface_global;
4185		desc->setter = wpas_dbus_setter_iface_global;
4186		desc->data = global_name;
4187	}
4188
4189	return 0;
4190
4191error:
4192	wpa_dbus_ctrl_iface_props_deinit(priv);
4193	return -1;
4194}
4195
4196
4197/**
4198 * wpas_dbus_register_interface - Register an interface with D-Bus
4199 * @wpa_s: wpa_supplicant interface structure
4200 * Returns: 0 on success, -1 on failure
4201 */
4202int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
4203{
4204	struct wpa_dbus_object_desc *obj_desc = NULL;
4205	struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
4206	int next;
4207
4208	/* Do nothing if the control interface is not turned on */
4209	if (ctrl_iface == NULL)
4210		return 0;
4211
4212	/* Create and set the interface's object path */
4213	wpa_s->dbus_new_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
4214	if (wpa_s->dbus_new_path == NULL)
4215		return -1;
4216	next = ctrl_iface->next_objid++;
4217	os_snprintf(wpa_s->dbus_new_path, WPAS_DBUS_OBJECT_PATH_MAX,
4218		    WPAS_DBUS_NEW_PATH_INTERFACES "/%u",
4219		    next);
4220
4221	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
4222	if (!obj_desc) {
4223		wpa_printf(MSG_ERROR,
4224			   "Not enough memory to create object description");
4225		goto err;
4226	}
4227
4228	wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
4229			   ctrl_iface->all_interface_properties,
4230			   wpas_dbus_interface_signals);
4231
4232	wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
4233		   wpa_s->dbus_new_path);
4234	if (wpa_dbus_register_object_per_iface(ctrl_iface,
4235					       wpa_s->dbus_new_path,
4236					       wpa_s->ifname, obj_desc))
4237		goto err;
4238
4239	wpas_dbus_signal_interface_added(wpa_s);
4240
4241	return 0;
4242
4243err:
4244	os_free(wpa_s->dbus_new_path);
4245	wpa_s->dbus_new_path = NULL;
4246	free_dbus_object_desc(obj_desc);
4247	return -1;
4248}
4249
4250
4251/**
4252 * wpas_dbus_unregister_interface - Unregister the interface from D-Bus
4253 * @wpa_s: wpa_supplicant interface structure
4254 * Returns: 0 on success, -1 on failure
4255 */
4256int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
4257{
4258	struct wpas_dbus_priv *ctrl_iface;
4259
4260	/* Do nothing if the control interface is not turned on */
4261	if (wpa_s == NULL || wpa_s->global == NULL)
4262		return 0;
4263	ctrl_iface = wpa_s->global->dbus;
4264	if (ctrl_iface == NULL || wpa_s->dbus_new_path == NULL)
4265		return 0;
4266
4267	wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
4268		   wpa_s->dbus_new_path);
4269
4270#ifdef CONFIG_AP
4271	if (wpa_s->preq_notify_peer) {
4272		wpas_dbus_unsubscribe_noc(ctrl_iface);
4273		os_free(wpa_s->preq_notify_peer);
4274		wpa_s->preq_notify_peer = NULL;
4275	}
4276#endif /* CONFIG_AP */
4277
4278	if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
4279						 wpa_s->dbus_new_path))
4280		return -1;
4281
4282	wpas_dbus_signal_interface_removed(wpa_s);
4283
4284	os_free(wpa_s->dbus_new_path);
4285	wpa_s->dbus_new_path = NULL;
4286
4287	return 0;
4288}
4289
4290#ifdef CONFIG_P2P
4291
4292static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
4293	{ "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
4294	  wpas_dbus_getter_p2p_peer_device_name,
4295	  NULL,
4296	  NULL
4297	},
4298	{ "Manufacturer", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
4299	  wpas_dbus_getter_p2p_peer_manufacturer,
4300	  NULL,
4301	  NULL
4302	},
4303	{ "ModelName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
4304	  wpas_dbus_getter_p2p_peer_modelname,
4305	  NULL,
4306	  NULL
4307	},
4308	{ "ModelNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
4309	  wpas_dbus_getter_p2p_peer_modelnumber,
4310	  NULL,
4311	  NULL
4312	},
4313	{ "SerialNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
4314	  wpas_dbus_getter_p2p_peer_serialnumber,
4315	  NULL,
4316	  NULL
4317	},
4318	{ "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
4319	  wpas_dbus_getter_p2p_peer_primary_device_type,
4320	  NULL,
4321	  NULL
4322	},
4323	{ "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q",
4324	  wpas_dbus_getter_p2p_peer_config_method,
4325	  NULL,
4326	  NULL
4327	},
4328	{ "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i",
4329	  wpas_dbus_getter_p2p_peer_level,
4330	  NULL,
4331	  NULL
4332	},
4333	{ "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
4334	  wpas_dbus_getter_p2p_peer_device_capability,
4335	  NULL,
4336	  NULL
4337	},
4338	{ "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
4339	  wpas_dbus_getter_p2p_peer_group_capability,
4340	  NULL,
4341	  NULL
4342	},
4343	{ "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
4344	  wpas_dbus_getter_p2p_peer_secondary_device_types,
4345	  NULL,
4346	  NULL
4347	},
4348	{ "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
4349	  wpas_dbus_getter_p2p_peer_vendor_extension,
4350	  NULL,
4351	  NULL
4352	},
4353	{ "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
4354	  wpas_dbus_getter_p2p_peer_ies,
4355	  NULL,
4356	  NULL
4357	},
4358	{ "DeviceAddress", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
4359	  wpas_dbus_getter_p2p_peer_device_address,
4360	  NULL,
4361	  NULL
4362	},
4363	{ "Groups", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ao",
4364	  wpas_dbus_getter_p2p_peer_groups,
4365	  NULL,
4366	  NULL
4367	},
4368	{ "VSIE", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
4369	  wpas_dbus_getter_p2p_peer_vsie,
4370	  NULL,
4371	  NULL
4372	},
4373	{ NULL, NULL, NULL, NULL, NULL, NULL }
4374};
4375
4376static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
4377	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
4378	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_P2P_PEER,
4379	  {
4380		  { "properties", "a{sv}", ARG_OUT },
4381		  END_ARGS
4382	  }
4383	},
4384	{ NULL, NULL, { END_ARGS } }
4385};
4386
4387/**
4388 * wpas_dbus_signal_peer - Send a peer related event signal
4389 * @wpa_s: %wpa_supplicant network interface data
4390 * @dev: peer device object
4391 * @interface: name of the interface emitting this signal.
4392 *	In case of peer objects, it would be emitted by either
4393 *	the "interface object" or by "peer objects"
4394 * @sig_name: signal name - DeviceFound
4395 * @properties: Whether to add a second argument with object properties
4396 *
4397 * Notify listeners about event related with p2p peer device
4398 */
4399static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
4400				  const u8 *dev_addr, const char *interface,
4401				  const char *sig_name, dbus_bool_t properties)
4402{
4403	struct wpas_dbus_priv *iface;
4404	DBusMessage *msg;
4405	DBusMessageIter iter;
4406	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
4407
4408	if (wpa_s->p2p_mgmt)
4409		wpa_s = wpa_s->parent;
4410
4411	iface = wpa_s->global->dbus;
4412
4413	/* Do nothing if the control interface is not turned on */
4414	if (iface == NULL || !wpa_s->dbus_new_path)
4415		return;
4416
4417	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
4418		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
4419		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
4420
4421	msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface,
4422				      sig_name);
4423	if (msg == NULL)
4424		return;
4425
4426	dbus_message_iter_init_append(msg, &iter);
4427	path = peer_obj_path;
4428	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
4429					    &path) ||
4430	    (properties && !wpa_dbus_get_object_properties(
4431		    iface, peer_obj_path, WPAS_DBUS_NEW_IFACE_P2P_PEER,
4432		    &iter)))
4433		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
4434	else
4435		dbus_connection_send(iface->con, msg, NULL);
4436
4437	dbus_message_unref(msg);
4438}
4439
4440
4441/**
4442 * wpas_dbus_signal_peer_found - Send a peer found signal
4443 * @wpa_s: %wpa_supplicant network interface data
4444 * @dev_addr: Peer P2P Device Address
4445 *
4446 * Notify listeners about find a p2p peer device found
4447 */
4448void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
4449					const u8 *dev_addr)
4450{
4451	wpas_dbus_signal_peer(wpa_s, dev_addr,
4452			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4453			      "DeviceFound", FALSE);
4454
4455	wpas_dbus_signal_peer(wpa_s, dev_addr,
4456			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4457			      "DeviceFoundProperties", TRUE);
4458}
4459
4460/**
4461 * wpas_dbus_signal_peer_lost - Send a peer lost signal
4462 * @wpa_s: %wpa_supplicant network interface data
4463 * @dev_addr: Peer P2P Device Address
4464 *
4465 * Notify listeners about lost a p2p peer device
4466 */
4467void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
4468				       const u8 *dev_addr)
4469{
4470	wpas_dbus_signal_peer(wpa_s, dev_addr,
4471			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4472			      "DeviceLost", FALSE);
4473}
4474
4475/**
4476 * wpas_dbus_register_peer - Register a discovered peer object with dbus
4477 * @wpa_s: wpa_supplicant interface structure
4478 * @dev_addr: P2P Device Address of the peer
4479 * Returns: 0 on success, -1 on failure
4480 *
4481 * Registers network representing object with dbus
4482 */
4483int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
4484{
4485	struct wpas_dbus_priv *ctrl_iface;
4486	struct wpa_dbus_object_desc *obj_desc;
4487	struct peer_handler_args *arg;
4488	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
4489
4490	/* Do nothing if the control interface is not turned on */
4491	if (wpa_s == NULL || wpa_s->global == NULL)
4492		return 0;
4493
4494	ctrl_iface = wpa_s->global->dbus;
4495	if (ctrl_iface == NULL)
4496		return 0;
4497
4498	wpa_s = wpa_s->parent->parent;
4499	if (!wpa_s->dbus_new_path)
4500		return 0;
4501
4502	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
4503		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
4504		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
4505
4506	wpa_printf(MSG_INFO, "dbus: Register peer object '%s'",
4507		   peer_obj_path);
4508	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
4509	if (!obj_desc) {
4510		wpa_printf(MSG_ERROR,
4511			   "Not enough memory to create object description");
4512		goto err;
4513	}
4514
4515	/* allocate memory for handlers arguments */
4516	arg = os_zalloc(sizeof(struct peer_handler_args));
4517	if (!arg) {
4518		wpa_printf(MSG_ERROR,
4519			   "Not enough memory to create arguments for method");
4520		goto err;
4521	}
4522
4523	arg->wpa_s = wpa_s;
4524	os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN);
4525
4526	wpas_dbus_register(obj_desc, arg, wpa_dbus_free,
4527			   NULL,
4528			   wpas_dbus_p2p_peer_properties,
4529			   wpas_dbus_p2p_peer_signals);
4530
4531	if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path,
4532					       wpa_s->ifname, obj_desc))
4533		goto err;
4534
4535	return 0;
4536
4537err:
4538	free_dbus_object_desc(obj_desc);
4539	return -1;
4540}
4541
4542/**
4543 * wpas_dbus_unregister_peer - Unregister a peer object with dbus
4544 * @wpa_s: wpa_supplicant interface structure
4545 * @dev_addr: p2p device addr
4546 * Returns: 0 on success, -1 on failure
4547 *
4548 * Registers network representing object with dbus
4549 */
4550int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
4551				  const u8 *dev_addr)
4552{
4553	struct wpas_dbus_priv *ctrl_iface;
4554	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
4555	int ret;
4556
4557	/* Do nothing if the control interface is not turned on */
4558	if (wpa_s == NULL || wpa_s->global == NULL)
4559		return 0;
4560
4561	wpa_s = wpa_s->parent->parent;
4562	if (!wpa_s->dbus_new_path)
4563		return 0;
4564
4565	ctrl_iface = wpa_s->global->dbus;
4566	if (ctrl_iface == NULL)
4567		return 0;
4568
4569	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
4570		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
4571		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
4572
4573	wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'",
4574		   peer_obj_path);
4575	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path);
4576
4577	return ret;
4578}
4579
4580
4581/**
4582 * wpas_dbus_signal_p2p_find_stopped - Send P2P Find stopped signal
4583 * @wpa_s: %wpa_supplicant network interface data
4584 *
4585 * Notify listeners about P2P Find stopped
4586 */
4587void wpas_dbus_signal_p2p_find_stopped(struct wpa_supplicant *wpa_s)
4588{
4589	struct wpas_dbus_priv *iface;
4590	DBusMessage *msg;
4591
4592	iface = wpa_s->global->dbus;
4593
4594	/* Do nothing if the control interface is not turned on */
4595	if (iface == NULL)
4596		return;
4597
4598	if (wpa_s->p2p_mgmt)
4599		wpa_s = wpa_s->parent;
4600
4601	if (!wpa_s->dbus_new_path)
4602		return;
4603
4604	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
4605				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
4606				      "FindStopped");
4607	if (msg == NULL)
4608		return;
4609
4610	dbus_connection_send(iface->con, msg, NULL);
4611
4612	dbus_message_unref(msg);
4613}
4614
4615
4616/**
4617 * wpas_dbus_signal_peer_groups_changed - Send peer group change property signal
4618 * @wpa_s: %wpa_supplicant network interface data
4619 * @dev_addr: P2P Device Address
4620 *
4621 * Notify listeners about peer Groups property changes.
4622 */
4623void wpas_dbus_signal_peer_groups_changed(struct wpa_supplicant *wpa_s,
4624					  const u8 *dev_addr)
4625{
4626	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
4627
4628	if (wpa_s->p2p_mgmt)
4629		wpa_s = wpa_s->parent;
4630
4631	if (!wpa_s->dbus_new_path)
4632		return;
4633	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
4634		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
4635		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
4636
4637	wpa_dbus_mark_property_changed(wpa_s->global->dbus, peer_obj_path,
4638				       WPAS_DBUS_NEW_IFACE_P2P_PEER, "Groups");
4639}
4640
4641
4642static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
4643	{ "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
4644	  wpas_dbus_getter_p2p_group_members,
4645	  NULL,
4646	  NULL
4647	},
4648	{ "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o",
4649	  wpas_dbus_getter_p2p_group,
4650	  NULL,
4651	  NULL
4652	},
4653	{ "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
4654	  wpas_dbus_getter_p2p_role,
4655	  NULL,
4656	  NULL
4657	},
4658	{ "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
4659	  wpas_dbus_getter_p2p_group_ssid,
4660	  NULL,
4661	  NULL
4662	},
4663	{ "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
4664	  wpas_dbus_getter_p2p_group_bssid,
4665	  NULL,
4666	  NULL
4667	},
4668	{ "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q",
4669	  wpas_dbus_getter_p2p_group_frequency,
4670	  NULL,
4671	  NULL
4672	},
4673	{ "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
4674	  wpas_dbus_getter_p2p_group_passphrase,
4675	  NULL,
4676	  NULL
4677	},
4678	{ "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
4679	  wpas_dbus_getter_p2p_group_psk,
4680	  NULL,
4681	  NULL
4682	},
4683	{ "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay",
4684	  wpas_dbus_getter_p2p_group_vendor_ext,
4685	  wpas_dbus_setter_p2p_group_vendor_ext,
4686	  NULL
4687	},
4688	{ NULL, NULL, NULL, NULL, NULL, NULL }
4689};
4690
4691static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
4692	{ "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
4693	  {
4694		  { "peer", "o", ARG_OUT },
4695		  END_ARGS
4696	  }
4697	},
4698	{ "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
4699	  {
4700		  { "peer", "o", ARG_OUT },
4701		  END_ARGS
4702	  }
4703	},
4704	{ NULL, NULL, { END_ARGS } }
4705};
4706
4707/**
4708 * wpas_dbus_register_p2p_group - Register a p2p group object with dbus
4709 * @wpa_s: wpa_supplicant interface structure
4710 * @ssid: SSID struct
4711 * Returns: 0 on success, -1 on failure
4712 *
4713 * Registers p2p group representing object with dbus
4714 */
4715void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
4716				  struct wpa_ssid *ssid)
4717{
4718	struct wpas_dbus_priv *ctrl_iface;
4719	struct wpa_dbus_object_desc *obj_desc;
4720	char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
4721
4722	/* Do nothing if the control interface is not turned on */
4723	if (wpa_s == NULL || wpa_s->global == NULL)
4724		return;
4725
4726	ctrl_iface = wpa_s->global->dbus;
4727	if (ctrl_iface == NULL)
4728		return;
4729
4730	if (wpa_s->dbus_groupobj_path) {
4731		wpa_printf(MSG_INFO, "%s: Group object '%s' already exists",
4732			   __func__, wpa_s->dbus_groupobj_path);
4733		return;
4734	}
4735
4736	if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
4737		return;
4738
4739	wpa_s->dbus_groupobj_path = os_strdup(group_obj_path);
4740	if (wpa_s->dbus_groupobj_path == NULL)
4741		return;
4742
4743	wpa_printf(MSG_INFO, "dbus: Register group object '%s'",
4744		   group_obj_path);
4745	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
4746	if (!obj_desc) {
4747		wpa_printf(MSG_ERROR,
4748			   "Not enough memory to create object description");
4749		goto err;
4750	}
4751
4752	wpas_dbus_register(obj_desc, wpa_s, NULL, NULL,
4753			   wpas_dbus_p2p_group_properties,
4754			   wpas_dbus_p2p_group_signals);
4755
4756	if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path,
4757					       wpa_s->ifname, obj_desc))
4758		goto err;
4759
4760	return;
4761
4762err:
4763	if (wpa_s->dbus_groupobj_path) {
4764		os_free(wpa_s->dbus_groupobj_path);
4765		wpa_s->dbus_groupobj_path = NULL;
4766	}
4767
4768	free_dbus_object_desc(obj_desc);
4769}
4770
4771/**
4772 * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus
4773 * @wpa_s: wpa_supplicant interface structure
4774 * @ssid: network name of the p2p group started
4775 */
4776void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
4777				    const struct wpa_ssid *ssid)
4778{
4779	struct wpas_dbus_priv *ctrl_iface;
4780
4781	/* Do nothing if the control interface is not turned on */
4782	if (wpa_s == NULL || wpa_s->global == NULL)
4783		return;
4784
4785	if (wpa_s->p2p_mgmt)
4786		wpa_s = wpa_s->parent;
4787
4788	ctrl_iface = wpa_s->global->dbus;
4789	if (ctrl_iface == NULL)
4790		return;
4791
4792	if (!wpa_s->dbus_groupobj_path) {
4793		wpa_printf(MSG_DEBUG,
4794			   "%s: Group object '%s' already unregistered",
4795			   __func__, wpa_s->dbus_groupobj_path);
4796		return;
4797	}
4798
4799	peer_groups_changed(wpa_s);
4800
4801	wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'",
4802		   wpa_s->dbus_groupobj_path);
4803
4804	wpa_dbus_unregister_object_per_iface(ctrl_iface,
4805					     wpa_s->dbus_groupobj_path);
4806
4807	os_free(wpa_s->dbus_groupobj_path);
4808	wpa_s->dbus_groupobj_path = NULL;
4809}
4810
4811static const struct wpa_dbus_property_desc
4812	wpas_dbus_persistent_group_properties[] = {
4813	{ "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
4814	  wpas_dbus_getter_persistent_group_properties,
4815	  wpas_dbus_setter_persistent_group_properties,
4816	  NULL
4817	},
4818	{ NULL, NULL, NULL, NULL, NULL, NULL }
4819};
4820
4821/* No signals intended for persistent group objects */
4822
4823/**
4824 * wpas_dbus_register_persistent_group - Register a configured(saved)
4825 *	persistent group with dbus
4826 * @wpa_s: wpa_supplicant interface structure
4827 * @ssid: persistent group (still represented as a network within wpa)
4828 *	  configuration data
4829 * Returns: 0 on success, -1 on failure
4830 *
4831 * Registers a persistent group representing object with dbus.
4832 */
4833int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
4834					struct wpa_ssid *ssid)
4835{
4836	struct wpas_dbus_priv *ctrl_iface;
4837	struct wpa_dbus_object_desc *obj_desc;
4838	struct network_handler_args *arg;
4839	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
4840
4841	/* Do nothing if the control interface is not turned on */
4842	if (wpa_s == NULL || wpa_s->global == NULL)
4843		return 0;
4844	wpa_s = wpa_s->parent->parent;
4845	if (!wpa_s->dbus_new_path)
4846		return 0;
4847
4848	/* Make sure ssid is a persistent group */
4849	if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
4850		return -1; /* should we return w/o complaining? */
4851
4852	if (wpa_s->p2p_mgmt)
4853		wpa_s = wpa_s->parent;
4854
4855	ctrl_iface = wpa_s->global->dbus;
4856	if (ctrl_iface == NULL)
4857		return 0;
4858
4859	/*
4860	 * Intentionally not coming up with different numbering scheme
4861	 * for persistent groups.
4862	 */
4863	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
4864		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
4865		    wpa_s->dbus_new_path, ssid->id);
4866
4867	wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'",
4868		   pgrp_obj_path);
4869	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
4870	if (!obj_desc) {
4871		wpa_printf(MSG_ERROR,
4872			   "dbus: Not enough memory to create object description");
4873		goto err;
4874	}
4875
4876	/*
4877	 * Reusing the same context structure as that for networks
4878	 * since these are represented using same data structure.
4879	 */
4880	/* allocate memory for handlers arguments */
4881	arg = os_zalloc(sizeof(struct network_handler_args));
4882	if (!arg) {
4883		wpa_printf(MSG_ERROR,
4884			   "dbus: Not enough memory to create arguments for method");
4885		goto err;
4886	}
4887
4888	arg->wpa_s = wpa_s;
4889	arg->ssid = ssid;
4890
4891	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
4892			   wpas_dbus_persistent_group_properties,
4893			   NULL);
4894
4895	if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path,
4896					       wpa_s->ifname, obj_desc))
4897		goto err;
4898
4899	wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id);
4900
4901	return 0;
4902
4903err:
4904	free_dbus_object_desc(obj_desc);
4905	return -1;
4906}
4907
4908
4909/**
4910 * wpas_dbus_unregister_persistent_group - Unregister a persistent_group
4911 *	from dbus
4912 * @wpa_s: wpa_supplicant interface structure
4913 * @nid: network id
4914 * Returns: 0 on success, -1 on failure
4915 *
4916 * Unregisters persistent group representing object from dbus
4917 *
4918 * NOTE: There is a slight issue with the semantics here. While the
4919 * implementation simply means the persistent group is unloaded from memory,
4920 * it should not get interpreted as the group is actually being erased/removed
4921 * from persistent storage as well.
4922 */
4923int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
4924					  int nid)
4925{
4926	struct wpas_dbus_priv *ctrl_iface;
4927	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
4928	int ret;
4929
4930	/* Do nothing if the control interface is not turned on */
4931	if (wpa_s == NULL || wpa_s->global == NULL)
4932		return 0;
4933
4934	wpa_s = wpa_s->parent->parent;
4935
4936	ctrl_iface = wpa_s->global->dbus;
4937	if (ctrl_iface == NULL || !wpa_s->dbus_new_path)
4938		return 0;
4939
4940	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
4941		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
4942		    wpa_s->dbus_new_path, nid);
4943
4944	wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'",
4945		   pgrp_obj_path);
4946	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path);
4947
4948	if (!ret)
4949		wpas_dbus_signal_persistent_group_removed(wpa_s, nid);
4950
4951	return ret;
4952}
4953
4954#endif /* CONFIG_P2P */
4955