1/*
2 * WPA Supplicant / dbus-based control interface
3 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4 * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
5 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6 *
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
9 */
10
11#include "includes.h"
12
13#include "common.h"
14#include "common/ieee802_11_defs.h"
15#include "wps/wps.h"
16#include "../config.h"
17#include "../wpa_supplicant_i.h"
18#include "../bss.h"
19#include "../wpas_glue.h"
20#include "dbus_new_helpers.h"
21#include "dbus_dict_helpers.h"
22#include "dbus_new.h"
23#include "dbus_new_handlers.h"
24#include "dbus_common_i.h"
25#include "dbus_new_handlers_p2p.h"
26#include "p2p/p2p.h"
27#include "../p2p_supplicant.h"
28
29#ifdef CONFIG_AP /* until needed by something else */
30
31/*
32 * NameOwnerChanged handling
33 *
34 * Some services we provide allow an application to register for
35 * a signal that it needs. While it can also unregister, we must
36 * be prepared for the case where the application simply crashes
37 * and thus doesn't clean up properly. The way to handle this in
38 * DBus is to register for the NameOwnerChanged signal which will
39 * signal an owner change to NULL if the peer closes the socket
40 * for whatever reason.
41 *
42 * Handle this signal via a filter function whenever necessary.
43 * The code below also handles refcounting in case in the future
44 * there will be multiple instances of this subscription scheme.
45 */
46static const char wpas_dbus_noc_filter_str[] =
47	"interface=org.freedesktop.DBus,member=NameOwnerChanged";
48
49
50static DBusHandlerResult noc_filter(DBusConnection *conn,
51				    DBusMessage *message, void *data)
52{
53	struct wpas_dbus_priv *priv = data;
54
55	if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
56		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
57
58	if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
59				   "NameOwnerChanged")) {
60		const char *name;
61		const char *prev_owner;
62		const char *new_owner;
63		DBusError derr;
64		struct wpa_supplicant *wpa_s;
65
66		dbus_error_init(&derr);
67
68		if (!dbus_message_get_args(message, &derr,
69					   DBUS_TYPE_STRING, &name,
70					   DBUS_TYPE_STRING, &prev_owner,
71					   DBUS_TYPE_STRING, &new_owner,
72					   DBUS_TYPE_INVALID)) {
73			/* Ignore this error */
74			dbus_error_free(&derr);
75			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
76		}
77
78		for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
79			if (wpa_s->preq_notify_peer != NULL &&
80			    os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
81			    (new_owner == NULL || os_strlen(new_owner) == 0)) {
82				/* probe request owner disconnected */
83				os_free(wpa_s->preq_notify_peer);
84				wpa_s->preq_notify_peer = NULL;
85				wpas_dbus_unsubscribe_noc(priv);
86			}
87		}
88	}
89
90	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
91}
92
93
94void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv)
95{
96	priv->dbus_noc_refcnt++;
97	if (priv->dbus_noc_refcnt > 1)
98		return;
99
100	if (!dbus_connection_add_filter(priv->con, noc_filter, priv, NULL)) {
101		wpa_printf(MSG_ERROR, "dbus: failed to add filter");
102		return;
103	}
104
105	dbus_bus_add_match(priv->con, wpas_dbus_noc_filter_str, NULL);
106}
107
108
109void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv)
110{
111	priv->dbus_noc_refcnt--;
112	if (priv->dbus_noc_refcnt > 0)
113		return;
114
115	dbus_bus_remove_match(priv->con, wpas_dbus_noc_filter_str, NULL);
116	dbus_connection_remove_filter(priv->con, noc_filter, priv);
117}
118
119#endif /* CONFIG_AP */
120
121
122/**
123 * wpas_dbus_signal_interface - Send a interface related event signal
124 * @wpa_s: %wpa_supplicant network interface data
125 * @sig_name: signal name - InterfaceAdded or InterfaceRemoved
126 * @properties: Whether to add second argument with object properties
127 *
128 * Notify listeners about event related with interface
129 */
130static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
131				       const char *sig_name, int properties)
132{
133	struct wpas_dbus_priv *iface;
134	DBusMessage *msg;
135	DBusMessageIter iter;
136
137	iface = wpa_s->global->dbus;
138
139	/* Do nothing if the control interface is not turned on */
140	if (iface == NULL || !wpa_s->dbus_new_path)
141		return;
142
143	msg = dbus_message_new_signal(WPAS_DBUS_NEW_PATH,
144				      WPAS_DBUS_NEW_INTERFACE, sig_name);
145	if (msg == NULL)
146		return;
147
148	dbus_message_iter_init_append(msg, &iter);
149	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
150					    &wpa_s->dbus_new_path) ||
151	    (properties &&
152	     !wpa_dbus_get_object_properties(
153		     iface, wpa_s->dbus_new_path,
154		     WPAS_DBUS_NEW_IFACE_INTERFACE, &iter)))
155		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
156	else
157		dbus_connection_send(iface->con, msg, NULL);
158	dbus_message_unref(msg);
159}
160
161
162/**
163 * wpas_dbus_signal_interface_added - Send a interface created signal
164 * @wpa_s: %wpa_supplicant network interface data
165 *
166 * Notify listeners about creating new interface
167 */
168static void wpas_dbus_signal_interface_added(struct wpa_supplicant *wpa_s)
169{
170	wpas_dbus_signal_interface(wpa_s, "InterfaceAdded", TRUE);
171}
172
173
174/**
175 * wpas_dbus_signal_interface_removed - Send a interface removed signal
176 * @wpa_s: %wpa_supplicant network interface data
177 *
178 * Notify listeners about removing interface
179 */
180static void wpas_dbus_signal_interface_removed(struct wpa_supplicant *wpa_s)
181{
182	wpas_dbus_signal_interface(wpa_s, "InterfaceRemoved", FALSE);
183
184}
185
186
187/**
188 * wpas_dbus_signal_scan_done - send scan done signal
189 * @wpa_s: %wpa_supplicant network interface data
190 * @success: indicates if scanning succeed or failed
191 *
192 * Notify listeners about finishing a scan
193 */
194void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success)
195{
196	struct wpas_dbus_priv *iface;
197	DBusMessage *msg;
198	dbus_bool_t succ;
199
200	iface = wpa_s->global->dbus;
201
202	/* Do nothing if the control interface is not turned on */
203	if (iface == NULL || !wpa_s->dbus_new_path)
204		return;
205
206	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
207				      WPAS_DBUS_NEW_IFACE_INTERFACE,
208				      "ScanDone");
209	if (msg == NULL)
210		return;
211
212	succ = success ? TRUE : FALSE;
213	if (dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &succ,
214				     DBUS_TYPE_INVALID))
215		dbus_connection_send(iface->con, msg, NULL);
216	else
217		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
218	dbus_message_unref(msg);
219}
220
221
222/**
223 * wpas_dbus_signal_bss - Send a BSS related event signal
224 * @wpa_s: %wpa_supplicant network interface data
225 * @bss_obj_path: BSS object path
226 * @sig_name: signal name - BSSAdded or BSSRemoved
227 * @properties: Whether to add second argument with object properties
228 *
229 * Notify listeners about event related with BSS
230 */
231static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
232				 const char *bss_obj_path,
233				 const char *sig_name, int properties)
234{
235	struct wpas_dbus_priv *iface;
236	DBusMessage *msg;
237	DBusMessageIter iter;
238
239	iface = wpa_s->global->dbus;
240
241	/* Do nothing if the control interface is not turned on */
242	if (iface == NULL || !wpa_s->dbus_new_path)
243		return;
244
245	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
246				      WPAS_DBUS_NEW_IFACE_INTERFACE,
247				      sig_name);
248	if (msg == NULL)
249		return;
250
251	dbus_message_iter_init_append(msg, &iter);
252	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
253					    &bss_obj_path) ||
254	    (properties &&
255	     !wpa_dbus_get_object_properties(iface, bss_obj_path,
256					     WPAS_DBUS_NEW_IFACE_BSS,
257					     &iter)))
258		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
259	else
260		dbus_connection_send(iface->con, msg, NULL);
261	dbus_message_unref(msg);
262}
263
264
265/**
266 * wpas_dbus_signal_bss_added - Send a BSS added signal
267 * @wpa_s: %wpa_supplicant network interface data
268 * @bss_obj_path: new BSS object path
269 *
270 * Notify listeners about adding new BSS
271 */
272static void wpas_dbus_signal_bss_added(struct wpa_supplicant *wpa_s,
273				       const char *bss_obj_path)
274{
275	wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSAdded", TRUE);
276}
277
278
279/**
280 * wpas_dbus_signal_bss_removed - Send a BSS removed signal
281 * @wpa_s: %wpa_supplicant network interface data
282 * @bss_obj_path: BSS object path
283 *
284 * Notify listeners about removing BSS
285 */
286static void wpas_dbus_signal_bss_removed(struct wpa_supplicant *wpa_s,
287					 const char *bss_obj_path)
288{
289	wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSRemoved", FALSE);
290}
291
292
293/**
294 * wpas_dbus_signal_blob - Send a blob related event signal
295 * @wpa_s: %wpa_supplicant network interface data
296 * @name: blob name
297 * @sig_name: signal name - BlobAdded or BlobRemoved
298 *
299 * Notify listeners about event related with blob
300 */
301static void wpas_dbus_signal_blob(struct wpa_supplicant *wpa_s,
302				  const char *name, const char *sig_name)
303{
304	struct wpas_dbus_priv *iface;
305	DBusMessage *msg;
306
307	iface = wpa_s->global->dbus;
308
309	/* Do nothing if the control interface is not turned on */
310	if (iface == NULL || !wpa_s->dbus_new_path)
311		return;
312
313	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
314				      WPAS_DBUS_NEW_IFACE_INTERFACE,
315				      sig_name);
316	if (msg == NULL)
317		return;
318
319	if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
320				     DBUS_TYPE_INVALID))
321		dbus_connection_send(iface->con, msg, NULL);
322	else
323		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
324	dbus_message_unref(msg);
325}
326
327
328/**
329 * wpas_dbus_signal_blob_added - Send a blob added signal
330 * @wpa_s: %wpa_supplicant network interface data
331 * @name: blob name
332 *
333 * Notify listeners about adding a new blob
334 */
335void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
336				 const char *name)
337{
338	wpas_dbus_signal_blob(wpa_s, name, "BlobAdded");
339}
340
341
342/**
343 * wpas_dbus_signal_blob_removed - Send a blob removed signal
344 * @wpa_s: %wpa_supplicant network interface data
345 * @name: blob name
346 *
347 * Notify listeners about removing blob
348 */
349void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
350				   const char *name)
351{
352	wpas_dbus_signal_blob(wpa_s, name, "BlobRemoved");
353}
354
355
356/**
357 * wpas_dbus_signal_network - Send a network related event signal
358 * @wpa_s: %wpa_supplicant network interface data
359 * @id: new network id
360 * @sig_name: signal name - NetworkAdded, NetworkRemoved or NetworkSelected
361 * @properties: determines if add second argument with object properties
362 *
363 * Notify listeners about event related with configured network
364 */
365static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
366				     int id, const char *sig_name,
367				     int properties)
368{
369	struct wpas_dbus_priv *iface;
370	DBusMessage *msg;
371	DBusMessageIter iter;
372	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
373
374	iface = wpa_s->global->dbus;
375
376	/* Do nothing if the control interface is not turned on */
377	if (iface == NULL || !wpa_s->dbus_new_path)
378		return;
379
380	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
381		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
382		    wpa_s->dbus_new_path, id);
383
384	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
385				      WPAS_DBUS_NEW_IFACE_INTERFACE,
386				      sig_name);
387	if (msg == NULL)
388		return;
389
390	dbus_message_iter_init_append(msg, &iter);
391	path = net_obj_path;
392	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
393					    &path) ||
394	    (properties &&
395	     !wpa_dbus_get_object_properties(
396		     iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
397		     &iter)))
398		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
399	else
400		dbus_connection_send(iface->con, msg, NULL);
401	dbus_message_unref(msg);
402}
403
404
405/**
406 * wpas_dbus_signal_network_added - Send a network added signal
407 * @wpa_s: %wpa_supplicant network interface data
408 * @id: new network id
409 *
410 * Notify listeners about adding new network
411 */
412static void wpas_dbus_signal_network_added(struct wpa_supplicant *wpa_s,
413					   int id)
414{
415	wpas_dbus_signal_network(wpa_s, id, "NetworkAdded", TRUE);
416}
417
418
419/**
420 * wpas_dbus_signal_network_removed - Send a network removed signal
421 * @wpa_s: %wpa_supplicant network interface data
422 * @id: network id
423 *
424 * Notify listeners about removing a network
425 */
426static void wpas_dbus_signal_network_removed(struct wpa_supplicant *wpa_s,
427					     int id)
428{
429	wpas_dbus_signal_network(wpa_s, id, "NetworkRemoved", FALSE);
430}
431
432
433/**
434 * wpas_dbus_signal_network_selected - Send a network selected signal
435 * @wpa_s: %wpa_supplicant network interface data
436 * @id: network id
437 *
438 * Notify listeners about selecting a network
439 */
440void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id)
441{
442	wpas_dbus_signal_network(wpa_s, id, "NetworkSelected", FALSE);
443}
444
445
446/**
447 * wpas_dbus_signal_network_request - Indicate that additional information
448 * (EAP password, etc.) is required to complete the association to this SSID
449 * @wpa_s: %wpa_supplicant network interface data
450 * @rtype: The specific additional information required
451 * @default_text: Optional description of required information
452 *
453 * Request additional information or passwords to complete an association
454 * request.
455 */
456void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
457				      struct wpa_ssid *ssid,
458				      enum wpa_ctrl_req_type rtype,
459				      const char *default_txt)
460{
461	struct wpas_dbus_priv *iface;
462	DBusMessage *msg;
463	DBusMessageIter iter;
464	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
465	const char *field, *txt = NULL, *net_ptr;
466
467	iface = wpa_s->global->dbus;
468
469	/* Do nothing if the control interface is not turned on */
470	if (iface == NULL || !wpa_s->dbus_new_path)
471		return;
472
473	field = wpa_supplicant_ctrl_req_to_string(rtype, default_txt, &txt);
474	if (field == NULL)
475		return;
476
477	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
478				      WPAS_DBUS_NEW_IFACE_INTERFACE,
479				      "NetworkRequest");
480	if (msg == NULL)
481		return;
482
483	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
484		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
485		    wpa_s->dbus_new_path, ssid->id);
486	net_ptr = &net_obj_path[0];
487
488	dbus_message_iter_init_append(msg, &iter);
489	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
490					    &net_ptr) ||
491	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field) ||
492	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
493		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
494	else
495		dbus_connection_send(iface->con, msg, NULL);
496	dbus_message_unref(msg);
497}
498
499
500/**
501 * wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes
502 * @wpa_s: %wpa_supplicant network interface data
503 * @ssid: configured network which Enabled property has changed
504 *
505 * Sends PropertyChanged signals containing new value of Enabled property
506 * for specified network
507 */
508void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
509					      struct wpa_ssid *ssid)
510{
511
512	char path[WPAS_DBUS_OBJECT_PATH_MAX];
513
514	if (!wpa_s->dbus_new_path)
515		return;
516	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
517		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
518		    wpa_s->dbus_new_path, ssid->id);
519
520	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
521				       WPAS_DBUS_NEW_IFACE_NETWORK, "Enabled");
522}
523
524
525#ifdef CONFIG_WPS
526
527/**
528 * wpas_dbus_signal_wps_event_pbc_overlap - Signals PBC overlap WPS event
529 * @wpa_s: %wpa_supplicant network interface data
530 *
531 * Sends Event dbus signal with name "pbc-overlap" and empty dict as arguments
532 */
533void wpas_dbus_signal_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
534{
535
536	DBusMessage *msg;
537	DBusMessageIter iter, dict_iter;
538	struct wpas_dbus_priv *iface;
539	char *key = "pbc-overlap";
540
541	iface = wpa_s->global->dbus;
542
543	/* Do nothing if the control interface is not turned on */
544	if (iface == NULL || !wpa_s->dbus_new_path)
545		return;
546
547	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
548				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
549	if (msg == NULL)
550		return;
551
552	dbus_message_iter_init_append(msg, &iter);
553
554	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
555	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
556	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
557		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
558	else
559		dbus_connection_send(iface->con, msg, NULL);
560
561	dbus_message_unref(msg);
562}
563
564
565/**
566 * wpas_dbus_signal_wps_event_success - Signals Success WPS event
567 * @wpa_s: %wpa_supplicant network interface data
568 *
569 * Sends Event dbus signal with name "success" and empty dict as arguments
570 */
571void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s)
572{
573
574	DBusMessage *msg;
575	DBusMessageIter iter, dict_iter;
576	struct wpas_dbus_priv *iface;
577	char *key = "success";
578
579	iface = wpa_s->global->dbus;
580
581	/* Do nothing if the control interface is not turned on */
582	if (iface == NULL || !wpa_s->dbus_new_path)
583		return;
584
585	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
586				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
587	if (msg == NULL)
588		return;
589
590	dbus_message_iter_init_append(msg, &iter);
591
592	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
593	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
594	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
595		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
596	else
597		dbus_connection_send(iface->con, msg, NULL);
598
599	dbus_message_unref(msg);
600}
601
602
603/**
604 * wpas_dbus_signal_wps_event_fail - Signals Fail WPS event
605 * @wpa_s: %wpa_supplicant network interface data
606 * @fail: WPS failure information
607 *
608 * Sends Event dbus signal with name "fail" and dictionary containing
609 * "msg field with fail message number (int32) as arguments
610 */
611void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s,
612				     struct wps_event_fail *fail)
613{
614
615	DBusMessage *msg;
616	DBusMessageIter iter, dict_iter;
617	struct wpas_dbus_priv *iface;
618	char *key = "fail";
619
620	iface = wpa_s->global->dbus;
621
622	/* Do nothing if the control interface is not turned on */
623	if (iface == NULL || !wpa_s->dbus_new_path)
624		return;
625
626	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
627				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
628	if (msg == NULL)
629		return;
630
631	dbus_message_iter_init_append(msg, &iter);
632
633	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
634	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
635	    !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
636	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
637		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
638	else
639		dbus_connection_send(iface->con, msg, NULL);
640
641	dbus_message_unref(msg);
642}
643
644
645/**
646 * wpas_dbus_signal_wps_event_m2d - Signals M2D WPS event
647 * @wpa_s: %wpa_supplicant network interface data
648 * @m2d: M2D event data information
649 *
650 * Sends Event dbus signal with name "m2d" and dictionary containing
651 * fields of wps_event_m2d structure.
652 */
653void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
654				    struct wps_event_m2d *m2d)
655{
656
657	DBusMessage *msg;
658	DBusMessageIter iter, dict_iter;
659	struct wpas_dbus_priv *iface;
660	char *key = "m2d";
661
662	iface = wpa_s->global->dbus;
663
664	/* Do nothing if the control interface is not turned on */
665	if (iface == NULL || !wpa_s->dbus_new_path)
666		return;
667
668	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
669				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
670	if (msg == NULL)
671		return;
672
673	dbus_message_iter_init_append(msg, &iter);
674
675	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
676	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
677	    !wpa_dbus_dict_append_uint16(&dict_iter, "config_methods",
678					 m2d->config_methods) ||
679	    !wpa_dbus_dict_append_byte_array(&dict_iter, "manufacturer",
680					     (const char *) m2d->manufacturer,
681					     m2d->manufacturer_len) ||
682	    !wpa_dbus_dict_append_byte_array(&dict_iter, "model_name",
683					     (const char *) m2d->model_name,
684					     m2d->model_name_len) ||
685	    !wpa_dbus_dict_append_byte_array(&dict_iter, "model_number",
686					     (const char *) m2d->model_number,
687					     m2d->model_number_len) ||
688	    !wpa_dbus_dict_append_byte_array(&dict_iter, "serial_number",
689					     (const char *)
690					     m2d->serial_number,
691					     m2d->serial_number_len) ||
692	    !wpa_dbus_dict_append_byte_array(&dict_iter, "dev_name",
693					     (const char *) m2d->dev_name,
694					     m2d->dev_name_len) ||
695	    !wpa_dbus_dict_append_byte_array(&dict_iter, "primary_dev_type",
696					     (const char *)
697					     m2d->primary_dev_type, 8) ||
698	    !wpa_dbus_dict_append_uint16(&dict_iter, "config_error",
699					 m2d->config_error) ||
700	    !wpa_dbus_dict_append_uint16(&dict_iter, "dev_password_id",
701					 m2d->dev_password_id) ||
702	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
703		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
704	else
705		dbus_connection_send(iface->con, msg, NULL);
706
707	dbus_message_unref(msg);
708}
709
710
711/**
712 * wpas_dbus_signal_wps_cred - Signals new credentials
713 * @wpa_s: %wpa_supplicant network interface data
714 * @cred: WPS Credential information
715 *
716 * Sends signal with credentials in directory argument
717 */
718void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
719			       const struct wps_credential *cred)
720{
721	DBusMessage *msg;
722	DBusMessageIter iter, dict_iter;
723	struct wpas_dbus_priv *iface;
724	char *auth_type[5]; /* we have five possible authentication types */
725	int at_num = 0;
726	char *encr_type[3]; /* we have three possible encryption types */
727	int et_num = 0;
728
729	iface = wpa_s->global->dbus;
730
731	/* Do nothing if the control interface is not turned on */
732	if (iface == NULL || !wpa_s->dbus_new_path)
733		return;
734
735	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
736				      WPAS_DBUS_NEW_IFACE_WPS,
737				      "Credentials");
738	if (msg == NULL)
739		return;
740
741	dbus_message_iter_init_append(msg, &iter);
742	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
743		goto nomem;
744
745	if (cred->auth_type & WPS_AUTH_OPEN)
746		auth_type[at_num++] = "open";
747	if (cred->auth_type & WPS_AUTH_WPAPSK)
748		auth_type[at_num++] = "wpa-psk";
749	if (cred->auth_type & WPS_AUTH_WPA)
750		auth_type[at_num++] = "wpa-eap";
751	if (cred->auth_type & WPS_AUTH_WPA2)
752		auth_type[at_num++] = "wpa2-eap";
753	if (cred->auth_type & WPS_AUTH_WPA2PSK)
754		auth_type[at_num++] = "wpa2-psk";
755
756	if (cred->encr_type & WPS_ENCR_NONE)
757		encr_type[et_num++] = "none";
758	if (cred->encr_type & WPS_ENCR_TKIP)
759		encr_type[et_num++] = "tkip";
760	if (cred->encr_type & WPS_ENCR_AES)
761		encr_type[et_num++] = "aes";
762
763	if ((wpa_s->current_ssid &&
764	     !wpa_dbus_dict_append_byte_array(
765		     &dict_iter, "BSSID",
766		     (const char *) wpa_s->current_ssid->bssid, ETH_ALEN)) ||
767	    !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
768					     (const char *) cred->ssid,
769					     cred->ssid_len) ||
770	    !wpa_dbus_dict_append_string_array(&dict_iter, "AuthType",
771					       (const char **) auth_type,
772					       at_num) ||
773	    !wpa_dbus_dict_append_string_array(&dict_iter, "EncrType",
774					       (const char **) encr_type,
775					       et_num) ||
776	    !wpa_dbus_dict_append_byte_array(&dict_iter, "Key",
777					     (const char *) cred->key,
778					     cred->key_len) ||
779	    !wpa_dbus_dict_append_uint32(&dict_iter, "KeyIndex",
780					 cred->key_idx) ||
781	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
782		goto nomem;
783
784	dbus_connection_send(iface->con, msg, NULL);
785
786nomem:
787	dbus_message_unref(msg);
788}
789
790#endif /* CONFIG_WPS */
791
792void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
793				    int depth, const char *subject,
794				    const char *altsubject[],
795				    int num_altsubject,
796				    const char *cert_hash,
797				    const struct wpabuf *cert)
798{
799	struct wpas_dbus_priv *iface;
800	DBusMessage *msg;
801	DBusMessageIter iter, dict_iter;
802
803	iface = wpa_s->global->dbus;
804
805	/* Do nothing if the control interface is not turned on */
806	if (iface == NULL || !wpa_s->dbus_new_path)
807		return;
808
809	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
810				      WPAS_DBUS_NEW_IFACE_INTERFACE,
811				      "Certification");
812	if (msg == NULL)
813		return;
814
815	dbus_message_iter_init_append(msg, &iter);
816	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
817	    !wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
818	    !wpa_dbus_dict_append_string(&dict_iter, "subject", subject) ||
819	    (altsubject && num_altsubject &&
820	     !wpa_dbus_dict_append_string_array(&dict_iter, "altsubject",
821						altsubject, num_altsubject)) ||
822	    (cert_hash &&
823	     !wpa_dbus_dict_append_string(&dict_iter, "cert_hash",
824					  cert_hash)) ||
825	    (cert &&
826	     !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
827					      wpabuf_head(cert),
828					      wpabuf_len(cert))) ||
829	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
830		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
831	else
832		dbus_connection_send(iface->con, msg, NULL);
833	dbus_message_unref(msg);
834}
835
836
837void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
838				 const char *status, const char *parameter)
839{
840	struct wpas_dbus_priv *iface;
841	DBusMessage *msg;
842	DBusMessageIter iter;
843
844	iface = wpa_s->global->dbus;
845
846	/* Do nothing if the control interface is not turned on */
847	if (iface == NULL || !wpa_s->dbus_new_path)
848		return;
849
850	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
851				      WPAS_DBUS_NEW_IFACE_INTERFACE,
852				      "EAP");
853	if (msg == NULL)
854		return;
855
856	dbus_message_iter_init_append(msg, &iter);
857
858	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status) ||
859	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
860					    &parameter))
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
868/**
869 * wpas_dbus_signal_sta - Send a station related event signal
870 * @wpa_s: %wpa_supplicant network interface data
871 * @sta: station mac address
872 * @sig_name: signal name - StaAuthorized or StaDeauthorized
873 *
874 * Notify listeners about event related with station
875 */
876static void wpas_dbus_signal_sta(struct wpa_supplicant *wpa_s,
877				 const u8 *sta, const char *sig_name)
878{
879	struct wpas_dbus_priv *iface;
880	DBusMessage *msg;
881	char sta_mac[WPAS_DBUS_OBJECT_PATH_MAX];
882	char *dev_mac;
883
884	os_snprintf(sta_mac, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(sta));
885	dev_mac = sta_mac;
886
887	iface = wpa_s->global->dbus;
888
889	/* Do nothing if the control interface is not turned on */
890	if (iface == NULL || !wpa_s->dbus_new_path)
891		return;
892
893	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
894				      WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
895	if (msg == NULL)
896		return;
897
898	if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &dev_mac,
899				     DBUS_TYPE_INVALID))
900		dbus_connection_send(iface->con, msg, NULL);
901	else
902		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
903	dbus_message_unref(msg);
904
905	wpa_printf(MSG_DEBUG, "dbus: Station MAC address '%s' '%s'",
906		   sta_mac, sig_name);
907}
908
909
910/**
911 * wpas_dbus_signal_sta_authorized - Send a STA authorized signal
912 * @wpa_s: %wpa_supplicant network interface data
913 * @sta: station mac address
914 *
915 * Notify listeners a new station has been authorized
916 */
917void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
918				     const u8 *sta)
919{
920	wpas_dbus_signal_sta(wpa_s, sta, "StaAuthorized");
921}
922
923
924/**
925 * wpas_dbus_signal_sta_deauthorized - Send a STA deauthorized signal
926 * @wpa_s: %wpa_supplicant network interface data
927 * @sta: station mac address
928 *
929 * Notify listeners a station has been deauthorized
930 */
931void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
932				       const u8 *sta)
933{
934	wpas_dbus_signal_sta(wpa_s, sta, "StaDeauthorized");
935}
936
937
938#ifdef CONFIG_P2P
939
940/**
941 * wpas_dbus_signal_p2p_group_removed - Signals P2P group was removed
942 * @wpa_s: %wpa_supplicant network interface data
943 * @role: role of this device (client or GO)
944 * Sends signal with i/f name and role as string arguments
945 */
946void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
947					const char *role)
948{
949	DBusMessage *msg;
950	DBusMessageIter iter, dict_iter;
951	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
952	struct wpa_supplicant *parent;
953
954	/* Do nothing if the control interface is not turned on */
955	if (iface == NULL)
956		return;
957
958	parent = wpa_s->parent;
959	if (parent->p2p_mgmt)
960		parent = parent->parent;
961
962	if (!wpa_s->dbus_groupobj_path || !wpa_s->dbus_new_path ||
963	    !parent->dbus_new_path)
964		return;
965
966	msg = dbus_message_new_signal(parent->dbus_new_path,
967				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
968				      "GroupFinished");
969	if (msg == NULL)
970		return;
971
972	dbus_message_iter_init_append(msg, &iter);
973	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
974	    !wpa_dbus_dict_append_object_path(&dict_iter,
975					      "interface_object",
976					      wpa_s->dbus_new_path) ||
977	    !wpa_dbus_dict_append_string(&dict_iter, "role", role) ||
978	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
979					      wpa_s->dbus_groupobj_path) ||
980	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
981		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
982	else
983		dbus_connection_send(iface->con, msg, NULL);
984	dbus_message_unref(msg);
985}
986
987
988/**
989 * wpas_dbus_signal_p2p_provision_discovery - Signals various PD events
990 *
991 * @dev_addr - who sent the request or responded to our request.
992 * @request - Will be 1 if request, 0 for response.
993 * @status - valid only in case of response
994 * @config_methods - wps config methods
995 * @generated_pin - pin to be displayed in case of WPS_CONFIG_DISPLAY method
996 *
997 * Sends following provision discovery related events:
998 *	ProvisionDiscoveryRequestDisplayPin
999 *	ProvisionDiscoveryResponseDisplayPin
1000 *	ProvisionDiscoveryRequestEnterPin
1001 *	ProvisionDiscoveryResponseEnterPin
1002 *	ProvisionDiscoveryPBCRequest
1003 *	ProvisionDiscoveryPBCResponse
1004 *
1005 *	TODO::
1006 *	ProvisionDiscoveryFailure (timeout case)
1007 */
1008void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
1009					      const u8 *dev_addr, int request,
1010					      enum p2p_prov_disc_status status,
1011					      u16 config_methods,
1012					      unsigned int generated_pin)
1013{
1014	DBusMessage *msg;
1015	DBusMessageIter iter;
1016	struct wpas_dbus_priv *iface;
1017	char *_signal;
1018	int add_pin = 0;
1019	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1020	int error_ret = 1;
1021	char pin[9], *p_pin = NULL;
1022
1023	iface = wpa_s->global->dbus;
1024
1025	/* Do nothing if the control interface is not turned on */
1026	if (iface == NULL)
1027		return;
1028
1029	if (wpa_s->p2p_mgmt)
1030		wpa_s = wpa_s->parent;
1031	if (!wpa_s->dbus_new_path)
1032		return;
1033
1034	if (request || !status) {
1035		if (config_methods & WPS_CONFIG_DISPLAY)
1036			_signal = request ?
1037				 "ProvisionDiscoveryRequestDisplayPin" :
1038				 "ProvisionDiscoveryResponseEnterPin";
1039		else if (config_methods & WPS_CONFIG_KEYPAD)
1040			_signal = request ?
1041				 "ProvisionDiscoveryRequestEnterPin" :
1042				 "ProvisionDiscoveryResponseDisplayPin";
1043		else if (config_methods & WPS_CONFIG_PUSHBUTTON)
1044			_signal = request ? "ProvisionDiscoveryPBCRequest" :
1045				   "ProvisionDiscoveryPBCResponse";
1046		else
1047			return; /* Unknown or un-supported method */
1048	} else {
1049		/* Explicit check for failure response */
1050		_signal = "ProvisionDiscoveryFailure";
1051	}
1052
1053	add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
1054		   (!request && !status &&
1055			(config_methods & WPS_CONFIG_KEYPAD)));
1056
1057	if (add_pin) {
1058		os_snprintf(pin, sizeof(pin), "%08d", generated_pin);
1059		p_pin = pin;
1060	}
1061
1062	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1063				      WPAS_DBUS_NEW_IFACE_P2PDEVICE, _signal);
1064	if (msg == NULL)
1065		return;
1066
1067	/* Check if this is a known peer */
1068	if (!p2p_peer_known(wpa_s->global->p2p, dev_addr))
1069		goto error;
1070
1071	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1072			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1073			COMPACT_MACSTR,
1074			wpa_s->dbus_new_path, MAC2STR(dev_addr));
1075
1076	path = peer_obj_path;
1077
1078	dbus_message_iter_init_append(msg, &iter);
1079
1080	if (!dbus_message_iter_append_basic(&iter,
1081					    DBUS_TYPE_OBJECT_PATH,
1082					    &path))
1083			goto error;
1084
1085	if (!request && status)
1086		/* Attach status to ProvisionDiscoveryFailure */
1087		error_ret = !dbus_message_iter_append_basic(&iter,
1088						    DBUS_TYPE_INT32,
1089						    &status);
1090	else
1091		error_ret = (add_pin &&
1092				 !dbus_message_iter_append_basic(&iter,
1093							DBUS_TYPE_STRING,
1094							&p_pin));
1095
1096error:
1097	if (!error_ret)
1098		dbus_connection_send(iface->con, msg, NULL);
1099	else
1100		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1101
1102	dbus_message_unref(msg);
1103}
1104
1105
1106/**
1107 * wpas_dbus_signal_p2p_go_neg_req - Signal P2P GO Negotiation Request RX
1108 * @wpa_s: %wpa_supplicant network interface data
1109 * @src: Source address of the message triggering this notification
1110 * @dev_passwd_id: WPS Device Password Id
1111 * @go_intent: Peer's GO Intent value
1112 *
1113 * Sends signal to notify that a peer P2P Device is requesting group owner
1114 * negotiation with us.
1115 */
1116void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
1117				     const u8 *src, u16 dev_passwd_id,
1118				     u8 go_intent)
1119{
1120	DBusMessage *msg;
1121	DBusMessageIter iter;
1122	struct wpas_dbus_priv *iface;
1123	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1124
1125	iface = wpa_s->global->dbus;
1126
1127	/* Do nothing if the control interface is not turned on */
1128	if (iface == NULL)
1129		return;
1130
1131	if (wpa_s->p2p_mgmt)
1132		wpa_s = wpa_s->parent;
1133	if (!wpa_s->dbus_new_path)
1134		return;
1135
1136	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1137		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1138		    wpa_s->dbus_new_path, MAC2STR(src));
1139	path = peer_obj_path;
1140
1141	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1142				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1143				      "GONegotiationRequest");
1144	if (msg == NULL)
1145		return;
1146
1147	dbus_message_iter_init_append(msg, &iter);
1148
1149	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
1150					    &path) ||
1151	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
1152					    &dev_passwd_id) ||
1153	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BYTE,
1154					    &go_intent))
1155		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1156	else
1157		dbus_connection_send(iface->con, msg, NULL);
1158
1159	dbus_message_unref(msg);
1160}
1161
1162
1163static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
1164					const struct wpa_ssid *ssid,
1165					char *group_obj_path)
1166{
1167	char group_name[3];
1168
1169	if (!wpa_s->dbus_new_path ||
1170	    os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
1171		return -1;
1172
1173	os_memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
1174	group_name[2] = '\0';
1175
1176	os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1177		    "%s/" WPAS_DBUS_NEW_P2P_GROUPS_PART "/%s",
1178		    wpa_s->dbus_new_path, group_name);
1179
1180	return 0;
1181}
1182
1183
1184struct group_changed_data {
1185	struct wpa_supplicant *wpa_s;
1186	struct p2p_peer_info *info;
1187};
1188
1189
1190static int match_group_where_peer_is_client(struct p2p_group *group,
1191					    void *user_data)
1192{
1193	struct group_changed_data *data = user_data;
1194	const struct p2p_group_config *cfg;
1195	struct wpa_supplicant *wpa_s_go;
1196
1197	if (!p2p_group_is_client_connected(group, data->info->p2p_device_addr))
1198		return 1;
1199
1200	cfg = p2p_group_get_config(group);
1201
1202	wpa_s_go = wpas_get_p2p_go_iface(data->wpa_s, cfg->ssid,
1203					 cfg->ssid_len);
1204	if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
1205		wpas_dbus_signal_peer_groups_changed(
1206			data->wpa_s->parent, data->info->p2p_device_addr);
1207		return 0;
1208	}
1209
1210	return 1;
1211}
1212
1213
1214static void signal_peer_groups_changed(struct p2p_peer_info *info,
1215				       void *user_data)
1216{
1217	struct group_changed_data *data = user_data;
1218	struct wpa_supplicant *wpa_s_go;
1219
1220	wpa_s_go = wpas_get_p2p_client_iface(data->wpa_s,
1221					     info->p2p_device_addr);
1222	if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
1223		wpas_dbus_signal_peer_groups_changed(data->wpa_s->parent,
1224						     info->p2p_device_addr);
1225		return;
1226	}
1227
1228	data->info = info;
1229	p2p_loop_on_all_groups(data->wpa_s->global->p2p,
1230			       match_group_where_peer_is_client, data);
1231	data->info = NULL;
1232}
1233
1234
1235static void peer_groups_changed(struct wpa_supplicant *wpa_s)
1236{
1237	struct group_changed_data data;
1238
1239	os_memset(&data, 0, sizeof(data));
1240	data.wpa_s = wpa_s;
1241
1242	p2p_loop_on_known_peers(wpa_s->global->p2p,
1243				signal_peer_groups_changed, &data);
1244}
1245
1246
1247/**
1248 * wpas_dbus_signal_p2p_group_started - Signals P2P group has
1249 * started. Emitted when a group is successfully started
1250 * irrespective of the role (client/GO) of the current device
1251 *
1252 * @wpa_s: %wpa_supplicant network interface data
1253 * @ssid: SSID object
1254 * @client: this device is P2P client
1255 * @network_id: network id of the group started, use instead of ssid->id
1256 *	to account for persistent groups
1257 */
1258void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
1259					const struct wpa_ssid *ssid,
1260					int client, int network_id)
1261{
1262	DBusMessage *msg;
1263	DBusMessageIter iter, dict_iter;
1264	struct wpas_dbus_priv *iface;
1265	struct wpa_supplicant *parent;
1266
1267	parent = wpa_s->parent;
1268	if (parent->p2p_mgmt)
1269		parent = parent->parent;
1270
1271	iface = parent->global->dbus;
1272
1273	/* Do nothing if the control interface is not turned on */
1274	if (iface == NULL || !parent->dbus_new_path || !wpa_s->dbus_new_path)
1275		return;
1276
1277	if (wpa_s->dbus_groupobj_path == NULL)
1278		return;
1279
1280	/* New interface has been created for this group */
1281	msg = dbus_message_new_signal(parent->dbus_new_path,
1282				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1283				      "GroupStarted");
1284	if (msg == NULL)
1285		return;
1286
1287	dbus_message_iter_init_append(msg, &iter);
1288	/*
1289	 * In case the device supports creating a separate interface the
1290	 * DBus client will need to know the object path for the interface
1291	 * object this group was created on, so include it here.
1292	 */
1293	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1294	    !wpa_dbus_dict_append_object_path(&dict_iter,
1295					      "interface_object",
1296					      wpa_s->dbus_new_path) ||
1297	    !wpa_dbus_dict_append_string(&dict_iter, "role",
1298					 client ? "client" : "GO") ||
1299	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
1300					      wpa_s->dbus_groupobj_path) ||
1301	    !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
1302		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1303	} else {
1304		dbus_connection_send(iface->con, msg, NULL);
1305		if (client)
1306			peer_groups_changed(wpa_s);
1307	}
1308	dbus_message_unref(msg);
1309}
1310
1311
1312/**
1313 * wpas_dbus_signal_p2p_go_neg_resp - Emit GONegotiation Success/Failure signal
1314 * @wpa_s: %wpa_supplicant network interface data
1315 * @res: Result of the GO Neg Request
1316 */
1317void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
1318				      struct p2p_go_neg_results *res)
1319{
1320	DBusMessage *msg;
1321	DBusMessageIter iter, dict_iter;
1322	DBusMessageIter iter_dict_entry, iter_dict_val, iter_dict_array;
1323	struct wpas_dbus_priv *iface;
1324	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1325	dbus_int32_t freqs[P2P_MAX_CHANNELS];
1326	dbus_int32_t *f_array = freqs;
1327
1328
1329	iface = wpa_s->global->dbus;
1330
1331	if (wpa_s->p2p_mgmt)
1332		wpa_s = wpa_s->parent;
1333
1334	os_memset(freqs, 0, sizeof(freqs));
1335	/* Do nothing if the control interface is not turned on */
1336	if (iface == NULL || !wpa_s->dbus_new_path)
1337		return;
1338
1339	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1340		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1341		    wpa_s->dbus_new_path, MAC2STR(res->peer_device_addr));
1342	path = peer_obj_path;
1343
1344	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1345				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1346				      res->status ? "GONegotiationFailure" :
1347						    "GONegotiationSuccess");
1348	if (msg == NULL)
1349		return;
1350
1351	dbus_message_iter_init_append(msg, &iter);
1352	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1353	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
1354					      path) ||
1355	    !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
1356		goto err;
1357
1358	if (!res->status) {
1359		int i = 0;
1360		int freq_list_num = 0;
1361
1362		if ((res->role_go &&
1363		     !wpa_dbus_dict_append_string(&dict_iter, "passphrase",
1364						  res->passphrase)) ||
1365		    !wpa_dbus_dict_append_string(&dict_iter, "role_go",
1366						 res->role_go ? "GO" :
1367						 "client") ||
1368		    !wpa_dbus_dict_append_int32(&dict_iter, "frequency",
1369						res->freq) ||
1370		    !wpa_dbus_dict_append_byte_array(&dict_iter, "ssid",
1371						     (const char *) res->ssid,
1372						     res->ssid_len) ||
1373		    !wpa_dbus_dict_append_byte_array(&dict_iter,
1374						     "peer_device_addr",
1375						     (const char *)
1376						     res->peer_device_addr,
1377						     ETH_ALEN) ||
1378		    !wpa_dbus_dict_append_byte_array(&dict_iter,
1379						     "peer_interface_addr",
1380						     (const char *)
1381						     res->peer_interface_addr,
1382						     ETH_ALEN) ||
1383		    !wpa_dbus_dict_append_string(&dict_iter, "wps_method",
1384						 p2p_wps_method_text(
1385							 res->wps_method)))
1386			goto err;
1387
1388		for (i = 0; i < P2P_MAX_CHANNELS; i++) {
1389			if (res->freq_list[i]) {
1390				freqs[i] = res->freq_list[i];
1391				freq_list_num++;
1392			}
1393		}
1394
1395		if (!wpa_dbus_dict_begin_array(&dict_iter,
1396					       "frequency_list",
1397					       DBUS_TYPE_INT32_AS_STRING,
1398					       &iter_dict_entry,
1399					       &iter_dict_val,
1400					       &iter_dict_array) ||
1401		    !dbus_message_iter_append_fixed_array(&iter_dict_array,
1402							  DBUS_TYPE_INT32,
1403							  &f_array,
1404							  freq_list_num) ||
1405		    !wpa_dbus_dict_end_array(&dict_iter,
1406					     &iter_dict_entry,
1407					     &iter_dict_val,
1408					     &iter_dict_array) ||
1409		    !wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
1410						res->persistent_group) ||
1411		    !wpa_dbus_dict_append_uint32(&dict_iter,
1412						 "peer_config_timeout",
1413						 res->peer_config_timeout))
1414			goto err;
1415	}
1416
1417	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
1418		goto err;
1419
1420	dbus_connection_send(iface->con, msg, NULL);
1421err:
1422	dbus_message_unref(msg);
1423}
1424
1425
1426/**
1427 * wpas_dbus_signal_p2p_invitation_result - Emit InvitationResult signal
1428 * @wpa_s: %wpa_supplicant network interface data
1429 * @status: Status of invitation process
1430 * @bssid: Basic Service Set Identifier
1431 */
1432void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
1433					    int status, const u8 *bssid)
1434{
1435	DBusMessage *msg;
1436	DBusMessageIter iter, dict_iter;
1437	struct wpas_dbus_priv *iface;
1438
1439	wpa_printf(MSG_DEBUG, "%s", __func__);
1440
1441	iface = wpa_s->global->dbus;
1442	/* Do nothing if the control interface is not turned on */
1443	if (iface == NULL)
1444		return;
1445
1446	if (wpa_s->p2p_mgmt)
1447		wpa_s = wpa_s->parent;
1448	if (!wpa_s->dbus_new_path)
1449		return;
1450
1451	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1452				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1453				      "InvitationResult");
1454
1455	if (msg == NULL)
1456		return;
1457
1458	dbus_message_iter_init_append(msg, &iter);
1459	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1460	    !wpa_dbus_dict_append_int32(&dict_iter, "status", status) ||
1461	    (bssid &&
1462	     !wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
1463					      (const char *) bssid,
1464					      ETH_ALEN)) ||
1465	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
1466		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1467	else
1468		dbus_connection_send(iface->con, msg, NULL);
1469	dbus_message_unref(msg);
1470}
1471
1472
1473/**
1474 *
1475 * Method to emit a signal for a peer joining the group.
1476 * The signal will carry path to the group member object
1477 * constructed using p2p i/f addr used for connecting.
1478 *
1479 * @wpa_s: %wpa_supplicant network interface data
1480 * @peer_addr: P2P Device Address of the peer joining the group
1481 */
1482void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
1483				      const u8 *peer_addr)
1484{
1485	struct wpas_dbus_priv *iface;
1486	DBusMessage *msg;
1487	DBusMessageIter iter;
1488	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1489	struct wpa_supplicant *parent;
1490
1491	iface = wpa_s->global->dbus;
1492
1493	/* Do nothing if the control interface is not turned on */
1494	if (iface == NULL)
1495		return;
1496
1497	if (!wpa_s->dbus_groupobj_path)
1498		return;
1499
1500	parent = wpa_s->parent;
1501	if (parent->p2p_mgmt)
1502		parent = parent->parent;
1503	if (!parent->dbus_new_path)
1504		return;
1505
1506	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1507			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1508			COMPACT_MACSTR,
1509			parent->dbus_new_path, MAC2STR(peer_addr));
1510
1511	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
1512				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
1513				      "PeerJoined");
1514	if (msg == NULL)
1515		return;
1516
1517	dbus_message_iter_init_append(msg, &iter);
1518	path = peer_obj_path;
1519	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
1520					    &path)) {
1521		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1522	} else {
1523		dbus_connection_send(iface->con, msg, NULL);
1524		wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
1525	}
1526	dbus_message_unref(msg);
1527}
1528
1529
1530/**
1531 *
1532 * Method to emit a signal for a peer disconnecting the group.
1533 * The signal will carry path to the group member object
1534 * constructed using the P2P Device Address of the peer.
1535 *
1536 * @wpa_s: %wpa_supplicant network interface data
1537 * @peer_addr: P2P Device Address of the peer joining the group
1538 */
1539void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
1540					    const u8 *peer_addr)
1541{
1542	struct wpas_dbus_priv *iface;
1543	DBusMessage *msg;
1544	DBusMessageIter iter;
1545	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1546	struct wpa_supplicant *parent;
1547
1548	iface = wpa_s->global->dbus;
1549
1550	/* Do nothing if the control interface is not turned on */
1551	if (iface == NULL)
1552		return;
1553
1554	if (!wpa_s->dbus_groupobj_path)
1555		return;
1556
1557	parent = wpa_s->parent;
1558	if (parent->p2p_mgmt)
1559		parent = parent->parent;
1560	if (!parent->dbus_new_path)
1561		return;
1562
1563	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1564			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1565			COMPACT_MACSTR,
1566			parent->dbus_new_path, MAC2STR(peer_addr));
1567
1568	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
1569				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
1570				      "PeerDisconnected");
1571	if (msg == NULL)
1572		return;
1573
1574	dbus_message_iter_init_append(msg, &iter);
1575	path = peer_obj_path;
1576	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
1577					    &path)) {
1578		wpa_printf(MSG_ERROR,
1579			   "dbus: Failed to construct PeerDisconnected signal");
1580	} else {
1581		dbus_connection_send(iface->con, msg, NULL);
1582		wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
1583	}
1584	dbus_message_unref(msg);
1585}
1586
1587
1588/**
1589 *
1590 * Method to emit a signal for a service discovery request.
1591 * The signal will carry station address, frequency, dialog token,
1592 * update indicator and it tlvs
1593 *
1594 * @wpa_s: %wpa_supplicant network interface data
1595 * @sa: station addr (p2p i/f) of the peer
1596 * @dialog_token: service discovery request dialog token
1597 * @update_indic: service discovery request update indicator
1598 * @tlvs: service discovery request genrated byte array of tlvs
1599 * @tlvs_len: service discovery request tlvs length
1600 */
1601void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
1602				     int freq, const u8 *sa, u8 dialog_token,
1603				     u16 update_indic, const u8 *tlvs,
1604				     size_t tlvs_len)
1605{
1606	DBusMessage *msg;
1607	DBusMessageIter iter, dict_iter;
1608	struct wpas_dbus_priv *iface;
1609	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1610
1611	iface = wpa_s->global->dbus;
1612
1613	/* Do nothing if the control interface is not turned on */
1614	if (iface == NULL)
1615		return;
1616
1617	if (wpa_s->p2p_mgmt)
1618		wpa_s = wpa_s->parent;
1619	if (!wpa_s->dbus_new_path)
1620		return;
1621
1622	/* Check if this is a known peer */
1623	if (!p2p_peer_known(wpa_s->global->p2p, sa))
1624		return;
1625
1626	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1627				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1628				      "ServiceDiscoveryRequest");
1629	if (msg == NULL)
1630		return;
1631
1632	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1633		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1634		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
1635
1636	path = peer_obj_path;
1637
1638	dbus_message_iter_init_append(msg, &iter);
1639	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1640	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
1641					      path) ||
1642	    !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
1643	    !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
1644					dialog_token) ||
1645	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
1646					 update_indic) ||
1647	    !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
1648					     (const char *) tlvs,
1649					     tlvs_len) ||
1650	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
1651		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1652	else
1653		dbus_connection_send(iface->con, msg, NULL);
1654	dbus_message_unref(msg);
1655}
1656
1657
1658/**
1659 *
1660 * Method to emit a signal for a service discovery response.
1661 * The signal will carry station address, update indicator and it
1662 * tlvs
1663 *
1664 * @wpa_s: %wpa_supplicant network interface data
1665 * @sa: station addr (p2p i/f) of the peer
1666 * @update_indic: service discovery request update indicator
1667 * @tlvs: service discovery request genrated byte array of tlvs
1668 * @tlvs_len: service discovery request tlvs length
1669 */
1670void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
1671				      const u8 *sa, u16 update_indic,
1672				      const u8 *tlvs, size_t tlvs_len)
1673{
1674	DBusMessage *msg;
1675	DBusMessageIter iter, dict_iter;
1676	struct wpas_dbus_priv *iface;
1677	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1678
1679	iface = wpa_s->global->dbus;
1680
1681	/* Do nothing if the control interface is not turned on */
1682	if (iface == NULL)
1683		return;
1684
1685	if (wpa_s->p2p_mgmt)
1686		wpa_s = wpa_s->parent;
1687	if (!wpa_s->dbus_new_path)
1688		return;
1689
1690	/* Check if this is a known peer */
1691	if (!p2p_peer_known(wpa_s->global->p2p, sa))
1692		return;
1693
1694	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1695				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1696				      "ServiceDiscoveryResponse");
1697	if (msg == NULL)
1698		return;
1699
1700	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1701		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1702		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
1703
1704	path = peer_obj_path;
1705
1706	dbus_message_iter_init_append(msg, &iter);
1707	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1708	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
1709					      path) ||
1710	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
1711					 update_indic) ||
1712	    !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
1713					     (const char *) tlvs,
1714					     tlvs_len) ||
1715	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
1716		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1717	else
1718		dbus_connection_send(iface->con, msg, NULL);
1719	dbus_message_unref(msg);
1720}
1721
1722
1723/**
1724 * wpas_dbus_signal_persistent_group - Send a persistent group related
1725 *	event signal
1726 * @wpa_s: %wpa_supplicant network interface data
1727 * @id: new persistent group id
1728 * @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved
1729 * @properties: determines if add second argument with object properties
1730 *
1731 * Notify listeners about an event related to persistent groups.
1732 */
1733static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
1734					      int id, const char *sig_name,
1735					      int properties)
1736{
1737	struct wpas_dbus_priv *iface;
1738	DBusMessage *msg;
1739	DBusMessageIter iter;
1740	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1741
1742	iface = wpa_s->global->dbus;
1743
1744	/* Do nothing if the control interface is not turned on */
1745	if (iface == NULL)
1746		return;
1747
1748	if (wpa_s->p2p_mgmt)
1749		wpa_s = wpa_s->parent;
1750	if (!wpa_s->dbus_new_path)
1751		return;
1752
1753	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1754		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
1755		    wpa_s->dbus_new_path, id);
1756
1757	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1758				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1759				      sig_name);
1760	if (msg == NULL)
1761		return;
1762
1763	dbus_message_iter_init_append(msg, &iter);
1764	path = pgrp_obj_path;
1765	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
1766					    &path) ||
1767	    (properties &&
1768	     !wpa_dbus_get_object_properties(
1769		     iface, pgrp_obj_path,
1770		     WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter)))
1771		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1772	else
1773		dbus_connection_send(iface->con, msg, NULL);
1774
1775	dbus_message_unref(msg);
1776}
1777
1778
1779/**
1780 * wpas_dbus_signal_persistent_group_added - Send a persistent_group
1781 *	added signal
1782 * @wpa_s: %wpa_supplicant network interface data
1783 * @id: new persistent group id
1784 *
1785 * Notify listeners about addition of a new persistent group.
1786 */
1787static void wpas_dbus_signal_persistent_group_added(
1788	struct wpa_supplicant *wpa_s, int id)
1789{
1790	wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded",
1791					  TRUE);
1792}
1793
1794
1795/**
1796 * wpas_dbus_signal_persistent_group_removed - Send a persistent_group
1797 *	removed signal
1798 * @wpa_s: %wpa_supplicant network interface data
1799 * @id: persistent group id
1800 *
1801 * Notify listeners about removal of a persistent group.
1802 */
1803static void wpas_dbus_signal_persistent_group_removed(
1804	struct wpa_supplicant *wpa_s, int id)
1805{
1806	wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved",
1807					  FALSE);
1808}
1809
1810
1811/**
1812 * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event
1813 * @wpa_s: %wpa_supplicant network interface data
1814 * @fail: WPS failure information
1815 *
1816 * Sends Event dbus signal with name "fail" and dictionary containing
1817 * "msg" field with fail message number (int32) as arguments
1818 */
1819void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
1820				     struct wps_event_fail *fail)
1821{
1822
1823	DBusMessage *msg;
1824	DBusMessageIter iter, dict_iter;
1825	struct wpas_dbus_priv *iface;
1826	char *key = "fail";
1827
1828	iface = wpa_s->global->dbus;
1829
1830	/* Do nothing if the control interface is not turned on */
1831	if (iface == NULL)
1832		return;
1833
1834	if (wpa_s->p2p_mgmt)
1835		wpa_s = wpa_s->parent;
1836
1837	if (!wpa_s->dbus_new_path)
1838		return;
1839	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
1840				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
1841				      "WpsFailed");
1842	if (msg == NULL)
1843		return;
1844
1845	dbus_message_iter_init_append(msg, &iter);
1846
1847	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
1848	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
1849	    !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
1850	    !wpa_dbus_dict_append_int16(&dict_iter, "config_error",
1851					fail->config_error) ||
1852	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
1853		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
1854	else
1855		dbus_connection_send(iface->con, msg, NULL);
1856
1857	dbus_message_unref(msg);
1858}
1859
1860#endif /* CONFIG_P2P */
1861
1862
1863/**
1864 * wpas_dbus_signal_prop_changed - Signals change of property
1865 * @wpa_s: %wpa_supplicant network interface data
1866 * @property: indicates which property has changed
1867 *
1868 * Sends PropertyChanged signals with path, interface and arguments
1869 * depending on which property has changed.
1870 */
1871void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
1872				   enum wpas_dbus_prop property)
1873{
1874	char *prop;
1875	dbus_bool_t flush;
1876
1877	if (wpa_s->dbus_new_path == NULL)
1878		return; /* Skip signal since D-Bus setup is not yet ready */
1879
1880	flush = FALSE;
1881	switch (property) {
1882	case WPAS_DBUS_PROP_AP_SCAN:
1883		prop = "ApScan";
1884		break;
1885	case WPAS_DBUS_PROP_SCANNING:
1886		prop = "Scanning";
1887		break;
1888	case WPAS_DBUS_PROP_STATE:
1889		prop = "State";
1890		break;
1891	case WPAS_DBUS_PROP_CURRENT_BSS:
1892		prop = "CurrentBSS";
1893		break;
1894	case WPAS_DBUS_PROP_CURRENT_NETWORK:
1895		prop = "CurrentNetwork";
1896		break;
1897	case WPAS_DBUS_PROP_BSSS:
1898		prop = "BSSs";
1899		break;
1900	case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
1901		prop = "CurrentAuthMode";
1902		break;
1903	case WPAS_DBUS_PROP_DISCONNECT_REASON:
1904		prop = "DisconnectReason";
1905		flush = TRUE;
1906		break;
1907	default:
1908		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
1909			   __func__, property);
1910		return;
1911	}
1912
1913	wpa_dbus_mark_property_changed(wpa_s->global->dbus,
1914				       wpa_s->dbus_new_path,
1915				       WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
1916	if (flush) {
1917		wpa_dbus_flush_object_changed_properties(
1918			wpa_s->global->dbus->con, wpa_s->dbus_new_path);
1919	}
1920}
1921
1922
1923/**
1924 * wpas_dbus_bss_signal_prop_changed - Signals change of BSS property
1925 * @wpa_s: %wpa_supplicant network interface data
1926 * @property: indicates which property has changed
1927 * @id: unique BSS identifier
1928 *
1929 * Sends PropertyChanged signals with path, interface, and arguments depending
1930 * on which property has changed.
1931 */
1932void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
1933				       enum wpas_dbus_bss_prop property,
1934				       unsigned int id)
1935{
1936	char path[WPAS_DBUS_OBJECT_PATH_MAX];
1937	char *prop;
1938
1939	if (!wpa_s->dbus_new_path)
1940		return;
1941
1942	switch (property) {
1943	case WPAS_DBUS_BSS_PROP_SIGNAL:
1944		prop = "Signal";
1945		break;
1946	case WPAS_DBUS_BSS_PROP_FREQ:
1947		prop = "Frequency";
1948		break;
1949	case WPAS_DBUS_BSS_PROP_MODE:
1950		prop = "Mode";
1951		break;
1952	case WPAS_DBUS_BSS_PROP_PRIVACY:
1953		prop = "Privacy";
1954		break;
1955	case WPAS_DBUS_BSS_PROP_RATES:
1956		prop = "Rates";
1957		break;
1958	case WPAS_DBUS_BSS_PROP_WPA:
1959		prop = "WPA";
1960		break;
1961	case WPAS_DBUS_BSS_PROP_RSN:
1962		prop = "RSN";
1963		break;
1964	case WPAS_DBUS_BSS_PROP_WPS:
1965		prop = "WPS";
1966		break;
1967	case WPAS_DBUS_BSS_PROP_IES:
1968		prop = "IEs";
1969		break;
1970	case WPAS_DBUS_BSS_PROP_AGE:
1971		prop = "Age";
1972		break;
1973	default:
1974		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
1975			   __func__, property);
1976		return;
1977	}
1978
1979	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1980		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
1981		    wpa_s->dbus_new_path, id);
1982
1983	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
1984				       WPAS_DBUS_NEW_IFACE_BSS, prop);
1985}
1986
1987
1988/**
1989 * wpas_dbus_signal_debug_level_changed - Signals change of debug param
1990 * @global: wpa_global structure
1991 *
1992 * Sends PropertyChanged signals informing that debug level has changed.
1993 */
1994void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
1995{
1996	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
1997				       WPAS_DBUS_NEW_INTERFACE,
1998				       "DebugLevel");
1999}
2000
2001
2002/**
2003 * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
2004 * @global: wpa_global structure
2005 *
2006 * Sends PropertyChanged signals informing that debug timestamp has changed.
2007 */
2008void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
2009{
2010	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
2011				       WPAS_DBUS_NEW_INTERFACE,
2012				       "DebugTimestamp");
2013}
2014
2015
2016/**
2017 * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
2018 * @global: wpa_global structure
2019 *
2020 * Sends PropertyChanged signals informing that debug show_keys has changed.
2021 */
2022void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
2023{
2024	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
2025				       WPAS_DBUS_NEW_INTERFACE,
2026				       "DebugShowKeys");
2027}
2028
2029
2030static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc,
2031			       void *priv,
2032			       WPADBusArgumentFreeFunction priv_free,
2033			       const struct wpa_dbus_method_desc *methods,
2034			       const struct wpa_dbus_property_desc *properties,
2035			       const struct wpa_dbus_signal_desc *signals)
2036{
2037	int n;
2038
2039	obj_desc->user_data = priv;
2040	obj_desc->user_data_free_func = priv_free;
2041	obj_desc->methods = methods;
2042	obj_desc->properties = properties;
2043	obj_desc->signals = signals;
2044
2045	for (n = 0; properties && properties->dbus_property; properties++)
2046		n++;
2047
2048	obj_desc->prop_changed_flags = os_zalloc(n);
2049	if (!obj_desc->prop_changed_flags)
2050		wpa_printf(MSG_DEBUG, "dbus: %s: can't register handlers",
2051			   __func__);
2052}
2053
2054
2055static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
2056	{ "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
2057	  (WPADBusMethodHandler) wpas_dbus_handler_create_interface,
2058	  {
2059		  { "args", "a{sv}", ARG_IN },
2060		  { "path", "o", ARG_OUT },
2061		  END_ARGS
2062	  }
2063	},
2064	{ "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
2065	  (WPADBusMethodHandler) wpas_dbus_handler_remove_interface,
2066	  {
2067		  { "path", "o", ARG_IN },
2068		  END_ARGS
2069	  }
2070	},
2071	{ "GetInterface", WPAS_DBUS_NEW_INTERFACE,
2072	  (WPADBusMethodHandler) wpas_dbus_handler_get_interface,
2073	  {
2074		  { "ifname", "s", ARG_IN },
2075		  { "path", "o", ARG_OUT },
2076		  END_ARGS
2077	  }
2078	},
2079	{ NULL, NULL, NULL, { END_ARGS } }
2080};
2081
2082static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
2083	{ "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
2084	  wpas_dbus_getter_debug_level,
2085	  wpas_dbus_setter_debug_level
2086	},
2087	{ "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
2088	  wpas_dbus_getter_debug_timestamp,
2089	  wpas_dbus_setter_debug_timestamp
2090	},
2091	{ "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
2092	  wpas_dbus_getter_debug_show_keys,
2093	  wpas_dbus_setter_debug_show_keys
2094	},
2095	{ "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
2096	  wpas_dbus_getter_interfaces,
2097	  NULL
2098	},
2099	{ "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
2100	  wpas_dbus_getter_eap_methods,
2101	  NULL
2102	},
2103	{ "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
2104	  wpas_dbus_getter_global_capabilities,
2105	  NULL
2106	},
2107#ifdef CONFIG_WIFI_DISPLAY
2108	{ "WFDIEs", WPAS_DBUS_NEW_INTERFACE, "ay",
2109	  wpas_dbus_getter_global_wfd_ies,
2110	  wpas_dbus_setter_global_wfd_ies
2111	},
2112#endif /* CONFIG_WIFI_DISPLAY */
2113	{ NULL, NULL, NULL, NULL, NULL }
2114};
2115
2116static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
2117	{ "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE,
2118	  {
2119		  { "path", "o", ARG_OUT },
2120		  { "properties", "a{sv}", ARG_OUT },
2121		  END_ARGS
2122	  }
2123	},
2124	{ "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE,
2125	  {
2126		  { "path", "o", ARG_OUT },
2127		  END_ARGS
2128	  }
2129	},
2130	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2131	{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
2132	  {
2133		  { "properties", "a{sv}", ARG_OUT },
2134		  END_ARGS
2135	  }
2136	},
2137	{ NULL, NULL, { END_ARGS } }
2138};
2139
2140
2141/**
2142 * wpas_dbus_ctrl_iface_init - Initialize dbus control interface
2143 * @global: Pointer to global data from wpa_supplicant_init()
2144 * Returns: 0 on success or -1 on failure
2145 *
2146 * Initialize the dbus control interface for wpa_supplicantand and start
2147 * receiving commands from external programs over the bus.
2148 */
2149int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
2150{
2151	struct wpa_dbus_object_desc *obj_desc;
2152	int ret;
2153
2154	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
2155	if (!obj_desc) {
2156		wpa_printf(MSG_ERROR,
2157			   "Not enough memory to create object description");
2158		return -1;
2159	}
2160
2161	wpas_dbus_register(obj_desc, priv->global, NULL,
2162			   wpas_dbus_global_methods,
2163			   wpas_dbus_global_properties,
2164			   wpas_dbus_global_signals);
2165
2166	wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'",
2167		   WPAS_DBUS_NEW_PATH);
2168	ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
2169				       WPAS_DBUS_NEW_SERVICE,
2170				       obj_desc);
2171	if (ret < 0)
2172		free_dbus_object_desc(obj_desc);
2173	else
2174		priv->dbus_new_initialized = 1;
2175
2176	return ret;
2177}
2178
2179
2180/**
2181 * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
2182 * wpa_supplicant
2183 * @iface: Pointer to dbus private data from wpas_dbus_init()
2184 *
2185 * Deinitialize the dbus control interface that was initialized with
2186 * wpas_dbus_ctrl_iface_init().
2187 */
2188void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface)
2189{
2190	if (!iface->dbus_new_initialized)
2191		return;
2192	wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'",
2193		   WPAS_DBUS_NEW_PATH);
2194	dbus_connection_unregister_object_path(iface->con,
2195					       WPAS_DBUS_NEW_PATH);
2196}
2197
2198
2199static void wpa_dbus_free(void *ptr)
2200{
2201	os_free(ptr);
2202}
2203
2204
2205static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
2206	{ "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
2207	  wpas_dbus_getter_network_properties,
2208	  wpas_dbus_setter_network_properties
2209	},
2210	{ "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
2211	  wpas_dbus_getter_enabled,
2212	  wpas_dbus_setter_enabled
2213	},
2214	{ NULL, NULL, NULL, NULL, NULL }
2215};
2216
2217
2218static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = {
2219	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2220	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
2221	  {
2222		  { "properties", "a{sv}", ARG_OUT },
2223		  END_ARGS
2224	  }
2225	},
2226	{ NULL, NULL, { END_ARGS } }
2227};
2228
2229
2230/**
2231 * wpas_dbus_register_network - Register a configured network with dbus
2232 * @wpa_s: wpa_supplicant interface structure
2233 * @ssid: network configuration data
2234 * Returns: 0 on success, -1 on failure
2235 *
2236 * Registers network representing object with dbus
2237 */
2238int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
2239			       struct wpa_ssid *ssid)
2240{
2241	struct wpas_dbus_priv *ctrl_iface;
2242	struct wpa_dbus_object_desc *obj_desc;
2243	struct network_handler_args *arg;
2244	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2245
2246#ifdef CONFIG_P2P
2247	/*
2248	 * If it is a persistent group register it as such.
2249	 * This is to handle cases where an interface is being initialized
2250	 * with a list of networks read from config.
2251	 */
2252	if (network_is_persistent_group(ssid))
2253		return wpas_dbus_register_persistent_group(wpa_s, ssid);
2254#endif /* CONFIG_P2P */
2255
2256	/* Do nothing if the control interface is not turned on */
2257	if (wpa_s == NULL || wpa_s->global == NULL || !wpa_s->dbus_new_path)
2258		return 0;
2259	ctrl_iface = wpa_s->global->dbus;
2260	if (ctrl_iface == NULL)
2261		return 0;
2262
2263	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2264		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
2265		    wpa_s->dbus_new_path, ssid->id);
2266
2267	wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'",
2268		   net_obj_path);
2269	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
2270	if (!obj_desc) {
2271		wpa_printf(MSG_ERROR,
2272			   "Not enough memory to create object description");
2273		goto err;
2274	}
2275
2276	/* allocate memory for handlers arguments */
2277	arg = os_zalloc(sizeof(struct network_handler_args));
2278	if (!arg) {
2279		wpa_printf(MSG_ERROR,
2280			   "Not enough memory to create arguments for method");
2281		goto err;
2282	}
2283
2284	arg->wpa_s = wpa_s;
2285	arg->ssid = ssid;
2286
2287	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
2288			   wpas_dbus_network_properties,
2289			   wpas_dbus_network_signals);
2290
2291	if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path,
2292					       wpa_s->ifname, obj_desc))
2293		goto err;
2294
2295	wpas_dbus_signal_network_added(wpa_s, ssid->id);
2296
2297	return 0;
2298
2299err:
2300	free_dbus_object_desc(obj_desc);
2301	return -1;
2302}
2303
2304
2305/**
2306 * wpas_dbus_unregister_network - Unregister a configured network from dbus
2307 * @wpa_s: wpa_supplicant interface structure
2308 * @nid: network id
2309 * Returns: 0 on success, -1 on failure
2310 *
2311 * Unregisters network representing object from dbus
2312 */
2313int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
2314{
2315	struct wpas_dbus_priv *ctrl_iface;
2316	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2317	int ret;
2318#ifdef CONFIG_P2P
2319	struct wpa_ssid *ssid;
2320
2321	ssid = wpa_config_get_network(wpa_s->conf, nid);
2322
2323	/* If it is a persistent group unregister it as such */
2324	if (ssid && network_is_persistent_group(ssid))
2325		return wpas_dbus_unregister_persistent_group(wpa_s, nid);
2326#endif /* CONFIG_P2P */
2327
2328	/* Do nothing if the control interface is not turned on */
2329	if (wpa_s->global == NULL || wpa_s->dbus_new_path == NULL)
2330		return 0;
2331	ctrl_iface = wpa_s->global->dbus;
2332	if (ctrl_iface == NULL)
2333		return 0;
2334
2335	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2336		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
2337		    wpa_s->dbus_new_path, nid);
2338
2339	wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'",
2340		   net_obj_path);
2341	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path);
2342
2343	if (!ret)
2344		wpas_dbus_signal_network_removed(wpa_s, nid);
2345
2346	return ret;
2347}
2348
2349
2350static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
2351	{ "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
2352	  wpas_dbus_getter_bss_ssid,
2353	  NULL
2354	},
2355	{ "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
2356	  wpas_dbus_getter_bss_bssid,
2357	  NULL
2358	},
2359	{ "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
2360	  wpas_dbus_getter_bss_privacy,
2361	  NULL
2362	},
2363	{ "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
2364	  wpas_dbus_getter_bss_mode,
2365	  NULL
2366	},
2367	{ "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
2368	  wpas_dbus_getter_bss_signal,
2369	  NULL
2370	},
2371	{ "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
2372	  wpas_dbus_getter_bss_frequency,
2373	  NULL
2374	},
2375	{ "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
2376	  wpas_dbus_getter_bss_rates,
2377	  NULL
2378	},
2379	{ "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
2380	  wpas_dbus_getter_bss_wpa,
2381	  NULL
2382	},
2383	{ "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
2384	  wpas_dbus_getter_bss_rsn,
2385	  NULL
2386	},
2387	{ "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
2388	  wpas_dbus_getter_bss_wps,
2389	  NULL
2390	},
2391	{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
2392	  wpas_dbus_getter_bss_ies,
2393	  NULL
2394	},
2395	{ "Age", WPAS_DBUS_NEW_IFACE_BSS, "u",
2396	  wpas_dbus_getter_bss_age,
2397	  NULL
2398	},
2399	{ NULL, NULL, NULL, NULL, NULL }
2400};
2401
2402
2403static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = {
2404	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2405	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS,
2406	  {
2407		  { "properties", "a{sv}", ARG_OUT },
2408		  END_ARGS
2409	  }
2410	},
2411	{ NULL, NULL, { END_ARGS } }
2412};
2413
2414
2415/**
2416 * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus
2417 * @wpa_s: wpa_supplicant interface structure
2418 * @bssid: scanned network bssid
2419 * @id: unique BSS identifier
2420 * Returns: 0 on success, -1 on failure
2421 *
2422 * Unregisters BSS representing object from dbus
2423 */
2424int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
2425			     u8 bssid[ETH_ALEN], unsigned int id)
2426{
2427	struct wpas_dbus_priv *ctrl_iface;
2428	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2429
2430	/* Do nothing if the control interface is not turned on */
2431	if (wpa_s == NULL || wpa_s->global == NULL || !wpa_s->dbus_new_path)
2432		return 0;
2433	ctrl_iface = wpa_s->global->dbus;
2434	if (ctrl_iface == NULL)
2435		return 0;
2436
2437	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2438		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
2439		    wpa_s->dbus_new_path, id);
2440
2441	wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'",
2442		   bss_obj_path);
2443	if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) {
2444		wpa_printf(MSG_ERROR, "dbus: Cannot unregister BSS object %s",
2445			   bss_obj_path);
2446		return -1;
2447	}
2448
2449	wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path);
2450	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
2451
2452	return 0;
2453}
2454
2455
2456/**
2457 * wpas_dbus_register_bss - Register a scanned BSS with dbus
2458 * @wpa_s: wpa_supplicant interface structure
2459 * @bssid: scanned network bssid
2460 * @id: unique BSS identifier
2461 * Returns: 0 on success, -1 on failure
2462 *
2463 * Registers BSS representing object with dbus
2464 */
2465int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
2466			   u8 bssid[ETH_ALEN], unsigned int id)
2467{
2468	struct wpas_dbus_priv *ctrl_iface;
2469	struct wpa_dbus_object_desc *obj_desc;
2470	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2471	struct bss_handler_args *arg;
2472
2473	/* Do nothing if the control interface is not turned on */
2474	if (wpa_s == NULL || wpa_s->global == NULL || !wpa_s->dbus_new_path)
2475		return 0;
2476	ctrl_iface = wpa_s->global->dbus;
2477	if (ctrl_iface == NULL)
2478		return 0;
2479
2480	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2481		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
2482		    wpa_s->dbus_new_path, id);
2483
2484	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
2485	if (!obj_desc) {
2486		wpa_printf(MSG_ERROR,
2487			   "Not enough memory to create object description");
2488		goto err;
2489	}
2490
2491	arg = os_zalloc(sizeof(struct bss_handler_args));
2492	if (!arg) {
2493		wpa_printf(MSG_ERROR,
2494			   "Not enough memory to create arguments for handler");
2495		goto err;
2496	}
2497	arg->wpa_s = wpa_s;
2498	arg->id = id;
2499
2500	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
2501			   wpas_dbus_bss_properties,
2502			   wpas_dbus_bss_signals);
2503
2504	wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'",
2505		   bss_obj_path);
2506	if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path,
2507					       wpa_s->ifname, obj_desc)) {
2508		wpa_printf(MSG_ERROR,
2509			   "Cannot register BSSID dbus object %s.",
2510			   bss_obj_path);
2511		goto err;
2512	}
2513
2514	wpas_dbus_signal_bss_added(wpa_s, bss_obj_path);
2515	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
2516
2517	return 0;
2518
2519err:
2520	free_dbus_object_desc(obj_desc);
2521	return -1;
2522}
2523
2524
2525static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
2526	{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
2527	  (WPADBusMethodHandler) wpas_dbus_handler_scan,
2528	  {
2529		  { "args", "a{sv}", ARG_IN },
2530		  END_ARGS
2531	  }
2532	},
2533	{ "SignalPoll", WPAS_DBUS_NEW_IFACE_INTERFACE,
2534	  (WPADBusMethodHandler) wpas_dbus_handler_signal_poll,
2535	  {
2536		  { "args", "a{sv}", ARG_OUT },
2537		  END_ARGS
2538	  }
2539	},
2540	{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
2541	  (WPADBusMethodHandler) wpas_dbus_handler_disconnect,
2542	  {
2543		  END_ARGS
2544	  }
2545	},
2546	{ "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
2547	  (WPADBusMethodHandler) wpas_dbus_handler_add_network,
2548	  {
2549		  { "args", "a{sv}", ARG_IN },
2550		  { "path", "o", ARG_OUT },
2551		  END_ARGS
2552	  }
2553	},
2554	{ "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
2555	  (WPADBusMethodHandler) wpas_dbus_handler_reassociate,
2556	  {
2557		  END_ARGS
2558	  }
2559	},
2560	{ "Reattach", WPAS_DBUS_NEW_IFACE_INTERFACE,
2561	  (WPADBusMethodHandler) wpas_dbus_handler_reattach,
2562	  {
2563		  END_ARGS
2564	  }
2565	},
2566	{ "Reconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
2567	  (WPADBusMethodHandler) wpas_dbus_handler_reconnect,
2568	  {
2569		  END_ARGS
2570	  }
2571	},
2572	{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
2573	  (WPADBusMethodHandler) wpas_dbus_handler_remove_network,
2574	  {
2575		  { "path", "o", ARG_IN },
2576		  END_ARGS
2577	  }
2578	},
2579	{ "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
2580	  (WPADBusMethodHandler) wpas_dbus_handler_remove_all_networks,
2581	  {
2582		  END_ARGS
2583	  }
2584	},
2585	{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
2586	  (WPADBusMethodHandler) wpas_dbus_handler_select_network,
2587	  {
2588		  { "path", "o", ARG_IN },
2589		  END_ARGS
2590	  }
2591	},
2592	{ "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
2593	  (WPADBusMethodHandler) wpas_dbus_handler_network_reply,
2594	  {
2595		  { "path", "o", ARG_IN },
2596		  { "field", "s", ARG_IN },
2597		  { "value", "s", ARG_IN },
2598		  END_ARGS
2599	  }
2600	},
2601#ifndef CONFIG_NO_CONFIG_BLOBS
2602	{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
2603	  (WPADBusMethodHandler) wpas_dbus_handler_add_blob,
2604	  {
2605		  { "name", "s", ARG_IN },
2606		  { "data", "ay", ARG_IN },
2607		  END_ARGS
2608	  }
2609	},
2610	{ "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
2611	  (WPADBusMethodHandler) wpas_dbus_handler_get_blob,
2612	  {
2613		  { "name", "s", ARG_IN },
2614		  { "data", "ay", ARG_OUT },
2615		  END_ARGS
2616	  }
2617	},
2618	{ "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
2619	  (WPADBusMethodHandler) wpas_dbus_handler_remove_blob,
2620	  {
2621		  { "name", "s", ARG_IN },
2622		  END_ARGS
2623	  }
2624	},
2625#endif /* CONFIG_NO_CONFIG_BLOBS */
2626	{ "SetPKCS11EngineAndModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE,
2627	  (WPADBusMethodHandler)
2628	  wpas_dbus_handler_set_pkcs11_engine_and_module_path,
2629	  {
2630		  { "pkcs11_engine_path", "s", ARG_IN },
2631		  { "pkcs11_module_path", "s", ARG_IN },
2632		  END_ARGS
2633	  }
2634	},
2635#ifdef CONFIG_WPS
2636	{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
2637	  (WPADBusMethodHandler) wpas_dbus_handler_wps_start,
2638	  {
2639		  { "args", "a{sv}", ARG_IN },
2640		  { "output", "a{sv}", ARG_OUT },
2641		  END_ARGS
2642	  }
2643	},
2644	{ "Cancel", WPAS_DBUS_NEW_IFACE_WPS,
2645	  (WPADBusMethodHandler) wpas_dbus_handler_wps_cancel,
2646	  {
2647		  END_ARGS
2648	  }
2649	},
2650#endif /* CONFIG_WPS */
2651#ifdef CONFIG_P2P
2652	{ "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2653	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_find,
2654	  {
2655		  { "args", "a{sv}", ARG_IN },
2656		  END_ARGS
2657	  }
2658	},
2659	{ "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2660	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_stop_find,
2661	  {
2662		  END_ARGS
2663	  }
2664	},
2665	{ "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2666	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_listen,
2667	  {
2668		  { "timeout", "i", ARG_IN },
2669		  END_ARGS
2670	  }
2671	},
2672	{ "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2673	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_extendedlisten,
2674	  {
2675		  { "args", "a{sv}", ARG_IN },
2676		  END_ARGS
2677	  }
2678	},
2679	{ "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2680	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_presence_request,
2681	  {
2682		  { "args", "a{sv}", ARG_IN },
2683		  END_ARGS
2684	  }
2685	},
2686	{ "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2687	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_prov_disc_req,
2688	  {
2689		  { "peer", "o", ARG_IN },
2690		  { "config_method", "s", ARG_IN },
2691		  END_ARGS
2692	  }
2693	},
2694	{ "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2695	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_connect,
2696	  {
2697		  { "args", "a{sv}", ARG_IN },
2698		  { "generated_pin", "s", ARG_OUT },
2699		  END_ARGS
2700	  }
2701	},
2702	{ "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2703	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_group_add,
2704	  {
2705		  { "args", "a{sv}", ARG_IN },
2706		  END_ARGS
2707	  }
2708	},
2709	{ "Cancel", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2710	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_cancel,
2711	  {
2712		  END_ARGS
2713	  }
2714	},
2715	{ "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2716	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_invite,
2717	  {
2718		  { "args", "a{sv}", ARG_IN },
2719		  END_ARGS
2720	  }
2721	},
2722	{ "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2723	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_disconnect,
2724	  {
2725		  END_ARGS
2726	  }
2727	},
2728	{ "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2729	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_rejectpeer,
2730	  {
2731		  { "peer", "o", ARG_IN },
2732		  END_ARGS
2733	  }
2734	},
2735	{ "RemoveClient", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2736	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_remove_client,
2737	  {
2738		  { "args", "a{sv}", ARG_IN },
2739		  END_ARGS
2740	  }
2741	},
2742	{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2743	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush,
2744	  {
2745		  END_ARGS
2746	  }
2747	},
2748	{ "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2749	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_add_service,
2750	  {
2751		  { "args", "a{sv}", ARG_IN },
2752		  END_ARGS
2753	  }
2754	},
2755	{ "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2756	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_delete_service,
2757	  {
2758		  { "args", "a{sv}", ARG_IN },
2759		  END_ARGS
2760	  }
2761	},
2762	{ "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2763	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush_service,
2764	  {
2765		  END_ARGS
2766	  }
2767	},
2768	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2769	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_req,
2770	  {
2771		  { "args", "a{sv}", ARG_IN },
2772		  { "ref", "t", ARG_OUT },
2773		  END_ARGS
2774	  }
2775	},
2776	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2777	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_res,
2778	  {
2779		  { "args", "a{sv}", ARG_IN },
2780		  END_ARGS
2781	  }
2782	},
2783	{ "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2784	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_cancel_req,
2785	  {
2786		  { "args", "t", ARG_IN },
2787		  END_ARGS
2788	  }
2789	},
2790	{ "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2791	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_update,
2792	  {
2793		  END_ARGS
2794	  }
2795	},
2796	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2797	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_serv_disc_external,
2798	  {
2799		  { "arg", "i", ARG_IN },
2800		  END_ARGS
2801	  }
2802	},
2803	{ "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2804	  (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group,
2805	  {
2806		  { "args", "a{sv}", ARG_IN },
2807		  { "path", "o", ARG_OUT },
2808		  END_ARGS
2809	  }
2810	},
2811	{ "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2812	  (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group,
2813	  {
2814		  { "path", "o", ARG_IN },
2815		  END_ARGS
2816	  }
2817	},
2818	{ "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2819	  (WPADBusMethodHandler)
2820	  wpas_dbus_handler_remove_all_persistent_groups,
2821	  {
2822		  END_ARGS
2823	  }
2824	},
2825#endif /* CONFIG_P2P */
2826	{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
2827	  (WPADBusMethodHandler) wpas_dbus_handler_flush_bss,
2828	  {
2829		  { "age", "u", ARG_IN },
2830		  END_ARGS
2831	  }
2832	},
2833#ifdef CONFIG_AP
2834	{ "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
2835	  (WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq,
2836	  {
2837		  END_ARGS
2838	  }
2839	},
2840	{ "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
2841	  (WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq,
2842	  {
2843		  END_ARGS
2844	  }
2845	},
2846#endif /* CONFIG_AP */
2847	{ "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE,
2848	  (WPADBusMethodHandler) wpas_dbus_handler_eap_logoff,
2849	  {
2850		  END_ARGS
2851	  }
2852	},
2853	{ "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE,
2854	  (WPADBusMethodHandler) wpas_dbus_handler_eap_logon,
2855	  {
2856		  END_ARGS
2857	  }
2858	},
2859#ifdef CONFIG_AUTOSCAN
2860	{ "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
2861	  (WPADBusMethodHandler) wpas_dbus_handler_autoscan,
2862	  {
2863		  { "arg", "s", ARG_IN },
2864		  END_ARGS
2865	  }
2866	},
2867#endif /* CONFIG_AUTOSCAN */
2868#ifdef CONFIG_TDLS
2869	{ "TDLSDiscover", WPAS_DBUS_NEW_IFACE_INTERFACE,
2870	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_discover,
2871	  {
2872		  { "peer_address", "s", ARG_IN },
2873		  END_ARGS
2874	  }
2875	},
2876	{ "TDLSSetup", WPAS_DBUS_NEW_IFACE_INTERFACE,
2877	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_setup,
2878	  {
2879		  { "peer_address", "s", ARG_IN },
2880		  END_ARGS
2881	  }
2882	},
2883	{ "TDLSStatus", WPAS_DBUS_NEW_IFACE_INTERFACE,
2884	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_status,
2885	  {
2886		  { "peer_address", "s", ARG_IN },
2887		  { "status", "s", ARG_OUT },
2888		  END_ARGS
2889	  }
2890	},
2891	{ "TDLSTeardown", WPAS_DBUS_NEW_IFACE_INTERFACE,
2892	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_teardown,
2893	  {
2894		  { "peer_address", "s", ARG_IN },
2895		  END_ARGS
2896	  }
2897	},
2898#endif /* CONFIG_TDLS */
2899	{ NULL, NULL, NULL, { END_ARGS } }
2900};
2901
2902static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
2903	{ "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
2904	  wpas_dbus_getter_capabilities,
2905	  NULL
2906	},
2907	{ "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2908	  wpas_dbus_getter_state,
2909	  NULL
2910	},
2911	{ "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
2912	  wpas_dbus_getter_scanning,
2913	  NULL
2914	},
2915	{ "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
2916	  wpas_dbus_getter_ap_scan,
2917	  wpas_dbus_setter_ap_scan
2918	},
2919	{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
2920	  wpas_dbus_getter_bss_expire_age,
2921	  wpas_dbus_setter_bss_expire_age
2922	},
2923	{ "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
2924	  wpas_dbus_getter_bss_expire_count,
2925	  wpas_dbus_setter_bss_expire_count
2926	},
2927	{ "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2928	  wpas_dbus_getter_country,
2929	  wpas_dbus_setter_country
2930	},
2931	{ "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2932	  wpas_dbus_getter_ifname,
2933	  NULL
2934	},
2935	{ "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2936	  wpas_dbus_getter_driver,
2937	  NULL
2938	},
2939	{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2940	  wpas_dbus_getter_bridge_ifname,
2941	  NULL
2942	},
2943	{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
2944	  wpas_dbus_getter_current_bss,
2945	  NULL
2946	},
2947	{ "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
2948	  wpas_dbus_getter_current_network,
2949	  NULL
2950	},
2951	{ "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2952	  wpas_dbus_getter_current_auth_mode,
2953	  NULL
2954	},
2955	{ "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
2956	  wpas_dbus_getter_blobs,
2957	  NULL
2958	},
2959	{ "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
2960	  wpas_dbus_getter_bsss,
2961	  NULL
2962	},
2963	{ "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
2964	  wpas_dbus_getter_networks,
2965	  NULL
2966	},
2967	{ "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
2968	  wpas_dbus_getter_fast_reauth,
2969	  wpas_dbus_setter_fast_reauth
2970	},
2971	{ "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
2972	  wpas_dbus_getter_scan_interval,
2973	  wpas_dbus_setter_scan_interval
2974	},
2975	{ "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2976	  wpas_dbus_getter_pkcs11_engine_path,
2977	  NULL
2978	},
2979	{ "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2980	  wpas_dbus_getter_pkcs11_module_path,
2981	  NULL
2982	},
2983#ifdef CONFIG_WPS
2984	{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
2985	  wpas_dbus_getter_process_credentials,
2986	  wpas_dbus_setter_process_credentials
2987	},
2988	{ "ConfigMethods", WPAS_DBUS_NEW_IFACE_WPS, "s",
2989	  wpas_dbus_getter_config_methods,
2990	  wpas_dbus_setter_config_methods
2991	},
2992#endif /* CONFIG_WPS */
2993#ifdef CONFIG_P2P
2994	{ "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
2995	  wpas_dbus_getter_p2p_device_config,
2996	  wpas_dbus_setter_p2p_device_config
2997	},
2998	{ "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
2999	  wpas_dbus_getter_p2p_peers,
3000	  NULL
3001	},
3002	{ "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
3003	  wpas_dbus_getter_p2p_role,
3004	  NULL
3005	},
3006	{ "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
3007	  wpas_dbus_getter_p2p_group,
3008	  NULL
3009	},
3010	{ "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
3011	  wpas_dbus_getter_p2p_peergo,
3012	  NULL
3013	},
3014	{ "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
3015	  wpas_dbus_getter_persistent_groups,
3016	  NULL
3017	},
3018#endif /* CONFIG_P2P */
3019	{ "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
3020	  wpas_dbus_getter_disconnect_reason,
3021	  NULL
3022	},
3023	{ NULL, NULL, NULL, NULL, NULL }
3024};
3025
3026static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
3027	{ "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
3028	  {
3029		  { "success", "b", ARG_OUT },
3030		  END_ARGS
3031	  }
3032	},
3033	{ "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
3034	  {
3035		  { "path", "o", ARG_OUT },
3036		  { "properties", "a{sv}", ARG_OUT },
3037		  END_ARGS
3038	  }
3039	},
3040	{ "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
3041	  {
3042		  { "path", "o", ARG_OUT },
3043		  END_ARGS
3044	  }
3045	},
3046	{ "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
3047	  {
3048		  { "name", "s", ARG_OUT },
3049		  END_ARGS
3050	  }
3051	},
3052	{ "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
3053	  {
3054		  { "name", "s", ARG_OUT },
3055		  END_ARGS
3056	  }
3057	},
3058	{ "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
3059	  {
3060		  { "path", "o", ARG_OUT },
3061		  { "properties", "a{sv}", ARG_OUT },
3062		  END_ARGS
3063	  }
3064	},
3065	{ "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
3066	  {
3067		  { "path", "o", ARG_OUT },
3068		  END_ARGS
3069	  }
3070	},
3071	{ "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE,
3072	  {
3073		  { "path", "o", ARG_OUT },
3074		  END_ARGS
3075	  }
3076	},
3077	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
3078	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
3079	  {
3080		  { "properties", "a{sv}", ARG_OUT },
3081		  END_ARGS
3082	  }
3083	},
3084#ifdef CONFIG_WPS
3085	{ "Event", WPAS_DBUS_NEW_IFACE_WPS,
3086	  {
3087		  { "name", "s", ARG_OUT },
3088		  { "args", "a{sv}", ARG_OUT },
3089		  END_ARGS
3090	  }
3091	},
3092	{ "Credentials", WPAS_DBUS_NEW_IFACE_WPS,
3093	  {
3094		  { "credentials", "a{sv}", ARG_OUT },
3095		  END_ARGS
3096	  }
3097	},
3098	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
3099	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
3100	  {
3101		  { "properties", "a{sv}", ARG_OUT },
3102		  END_ARGS
3103	  }
3104	},
3105#endif /* CONFIG_WPS */
3106#ifdef CONFIG_P2P
3107	{ "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3108	  {
3109		  { "path", "o", ARG_OUT },
3110		  END_ARGS
3111	  }
3112	},
3113	{ "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3114	  {
3115		  { "path", "o", ARG_OUT },
3116		  END_ARGS
3117	  }
3118	},
3119	{ "FindStopped", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3120	  {
3121		  END_ARGS
3122	  }
3123	},
3124	{ "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3125	  {
3126		  { "peer_object", "o", ARG_OUT },
3127		  { "pin", "s", ARG_OUT },
3128		  END_ARGS
3129	  }
3130	},
3131	{ "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3132	  {
3133		  { "peer_object", "o", ARG_OUT },
3134		  { "pin", "s", ARG_OUT },
3135		  END_ARGS
3136	  }
3137	},
3138	{ "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3139	  {
3140		  { "peer_object", "o", ARG_OUT },
3141		  END_ARGS
3142	  }
3143	},
3144	{ "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3145	  {
3146		  { "peer_object", "o", ARG_OUT },
3147		  END_ARGS
3148	  }
3149	},
3150	{ "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3151	  {
3152		  { "peer_object", "o", ARG_OUT },
3153		  END_ARGS
3154	  }
3155	},
3156	{ "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3157	  {
3158		  { "peer_object", "o", ARG_OUT },
3159		  END_ARGS
3160	  }
3161	},
3162	{ "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3163	  {
3164		  { "peer_object", "o", ARG_OUT },
3165		  { "status", "i", ARG_OUT },
3166		  END_ARGS
3167	  }
3168	},
3169	{ "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3170	  {
3171		  { "properties", "a{sv}", ARG_OUT },
3172		  END_ARGS
3173	  }
3174	},
3175	{ "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3176	  {
3177		  { "properties", "a{sv}", ARG_OUT },
3178		  END_ARGS
3179	  }
3180	},
3181	{ "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3182	  {
3183		  { "properties", "a{sv}", ARG_OUT },
3184		  END_ARGS
3185	  }
3186	},
3187	{ "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3188	  {
3189		  { "path", "o", ARG_OUT },
3190		  { "dev_passwd_id", "i", ARG_OUT },
3191		  { "device_go_intent", "y", ARG_OUT },
3192		  END_ARGS
3193	  }
3194	},
3195	{ "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3196	  {
3197		  { "invite_result", "a{sv}", ARG_OUT },
3198		  END_ARGS
3199	  }
3200	},
3201	{ "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3202	  {
3203		  { "properties", "a{sv}", ARG_OUT },
3204		  END_ARGS
3205	  }
3206	},
3207	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3208	  {
3209		  { "sd_request", "a{sv}", ARG_OUT },
3210		  END_ARGS
3211	  }
3212	},
3213	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3214	  {
3215		  { "sd_response", "a{sv}", ARG_OUT },
3216		  END_ARGS
3217	  }
3218	},
3219	{ "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3220	  {
3221		  { "path", "o", ARG_OUT },
3222		  { "properties", "a{sv}", ARG_OUT },
3223		  END_ARGS
3224	  }
3225	},
3226	{ "PersistentGroupRemoved", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3227	  {
3228		  { "path", "o", ARG_OUT },
3229		  END_ARGS
3230	  }
3231	},
3232	{ "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3233	  {
3234		  { "name", "s", ARG_OUT },
3235		  { "args", "a{sv}", ARG_OUT },
3236		  END_ARGS
3237	  }
3238	},
3239#endif /* CONFIG_P2P */
3240#ifdef CONFIG_AP
3241	{ "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
3242	  {
3243		  { "args", "a{sv}", ARG_OUT },
3244		  END_ARGS
3245	  }
3246	},
3247#endif /* CONFIG_AP */
3248	{ "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
3249	  {
3250		  { "certification", "a{sv}", ARG_OUT },
3251		  END_ARGS
3252	  }
3253	},
3254	{ "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE,
3255	  {
3256		  { "status", "s", ARG_OUT },
3257		  { "parameter", "s", ARG_OUT },
3258		  END_ARGS
3259	  }
3260	},
3261	{ "StaAuthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
3262	  {
3263		  { "name", "s", ARG_OUT },
3264		  END_ARGS
3265	  }
3266	},
3267	{ "StaDeauthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
3268	  {
3269		  { "name", "s", ARG_OUT },
3270		  END_ARGS
3271	  }
3272	},
3273	{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
3274	  {
3275		  { "path", "o", ARG_OUT },
3276		  { "field", "s", ARG_OUT },
3277		  { "text", "s", ARG_OUT },
3278		  END_ARGS
3279	  }
3280	},
3281	{ NULL, NULL, { END_ARGS } }
3282};
3283
3284
3285/**
3286 * wpas_dbus_register_interface - Register an interface with D-Bus
3287 * @wpa_s: wpa_supplicant interface structure
3288 * Returns: 0 on success, -1 on failure
3289 */
3290int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
3291{
3292
3293	struct wpa_dbus_object_desc *obj_desc = NULL;
3294	struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
3295	int next;
3296
3297	/* Do nothing if the control interface is not turned on */
3298	if (ctrl_iface == NULL)
3299		return 0;
3300
3301	/* Create and set the interface's object path */
3302	wpa_s->dbus_new_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3303	if (wpa_s->dbus_new_path == NULL)
3304		return -1;
3305	next = ctrl_iface->next_objid++;
3306	os_snprintf(wpa_s->dbus_new_path, WPAS_DBUS_OBJECT_PATH_MAX,
3307		    WPAS_DBUS_NEW_PATH_INTERFACES "/%u",
3308		    next);
3309
3310	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3311	if (!obj_desc) {
3312		wpa_printf(MSG_ERROR,
3313			   "Not enough memory to create object description");
3314		goto err;
3315	}
3316
3317	wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
3318			   wpas_dbus_interface_properties,
3319			   wpas_dbus_interface_signals);
3320
3321	wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
3322		   wpa_s->dbus_new_path);
3323	if (wpa_dbus_register_object_per_iface(ctrl_iface,
3324					       wpa_s->dbus_new_path,
3325					       wpa_s->ifname, obj_desc))
3326		goto err;
3327
3328	wpas_dbus_signal_interface_added(wpa_s);
3329
3330	return 0;
3331
3332err:
3333	os_free(wpa_s->dbus_new_path);
3334	wpa_s->dbus_new_path = NULL;
3335	free_dbus_object_desc(obj_desc);
3336	return -1;
3337}
3338
3339
3340/**
3341 * wpas_dbus_unregister_interface - Unregister the interface from D-Bus
3342 * @wpa_s: wpa_supplicant interface structure
3343 * Returns: 0 on success, -1 on failure
3344 */
3345int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
3346{
3347	struct wpas_dbus_priv *ctrl_iface;
3348
3349	/* Do nothing if the control interface is not turned on */
3350	if (wpa_s == NULL || wpa_s->global == NULL)
3351		return 0;
3352	ctrl_iface = wpa_s->global->dbus;
3353	if (ctrl_iface == NULL || wpa_s->dbus_new_path == NULL)
3354		return 0;
3355
3356	wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
3357		   wpa_s->dbus_new_path);
3358
3359#ifdef CONFIG_AP
3360	if (wpa_s->preq_notify_peer) {
3361		wpas_dbus_unsubscribe_noc(ctrl_iface);
3362		os_free(wpa_s->preq_notify_peer);
3363		wpa_s->preq_notify_peer = NULL;
3364	}
3365#endif /* CONFIG_AP */
3366
3367	if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
3368						 wpa_s->dbus_new_path))
3369		return -1;
3370
3371	wpas_dbus_signal_interface_removed(wpa_s);
3372
3373	os_free(wpa_s->dbus_new_path);
3374	wpa_s->dbus_new_path = NULL;
3375
3376	return 0;
3377}
3378
3379#ifdef CONFIG_P2P
3380
3381static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
3382	{ "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
3383	  wpas_dbus_getter_p2p_peer_device_name,
3384	  NULL
3385	},
3386	{ "Manufacturer", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
3387	  wpas_dbus_getter_p2p_peer_manufacturer,
3388	  NULL
3389	},
3390	{ "ModelName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
3391	  wpas_dbus_getter_p2p_peer_modelname,
3392	  NULL
3393	},
3394	{ "ModelNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
3395	  wpas_dbus_getter_p2p_peer_modelnumber,
3396	  NULL
3397	},
3398	{ "SerialNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
3399	  wpas_dbus_getter_p2p_peer_serialnumber,
3400	  NULL
3401	},
3402	{ "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
3403	  wpas_dbus_getter_p2p_peer_primary_device_type,
3404	  NULL
3405	},
3406	{ "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q",
3407	  wpas_dbus_getter_p2p_peer_config_method,
3408	  NULL
3409	},
3410	{ "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i",
3411	  wpas_dbus_getter_p2p_peer_level,
3412	  NULL
3413	},
3414	{ "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
3415	  wpas_dbus_getter_p2p_peer_device_capability,
3416	  NULL
3417	},
3418	{ "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
3419	  wpas_dbus_getter_p2p_peer_group_capability,
3420	  NULL
3421	},
3422	{ "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
3423	  wpas_dbus_getter_p2p_peer_secondary_device_types,
3424	  NULL
3425	},
3426	{ "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
3427	  wpas_dbus_getter_p2p_peer_vendor_extension,
3428	  NULL
3429	},
3430	{ "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
3431	  wpas_dbus_getter_p2p_peer_ies,
3432	  NULL
3433	},
3434	{ "DeviceAddress", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
3435	  wpas_dbus_getter_p2p_peer_device_address,
3436	  NULL
3437	},
3438	{ "Groups", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ao",
3439	  wpas_dbus_getter_p2p_peer_groups,
3440	  NULL
3441	},
3442	{ NULL, NULL, NULL, NULL, NULL }
3443};
3444
3445static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
3446	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
3447	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_P2P_PEER,
3448	  {
3449		  { "properties", "a{sv}", ARG_OUT },
3450		  END_ARGS
3451	  }
3452	},
3453	{ NULL, NULL, { END_ARGS } }
3454};
3455
3456/**
3457 * wpas_dbus_signal_peer - Send a peer related event signal
3458 * @wpa_s: %wpa_supplicant network interface data
3459 * @dev: peer device object
3460 * @interface: name of the interface emitting this signal.
3461 *	In case of peer objects, it would be emitted by either
3462 *	the "interface object" or by "peer objects"
3463 * @sig_name: signal name - DeviceFound
3464 *
3465 * Notify listeners about event related with newly found p2p peer device
3466 */
3467static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
3468				  const u8 *dev_addr, const char *interface,
3469				  const char *sig_name)
3470{
3471	struct wpas_dbus_priv *iface;
3472	DBusMessage *msg;
3473	DBusMessageIter iter;
3474	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
3475
3476	if (wpa_s->p2p_mgmt)
3477		wpa_s = wpa_s->parent;
3478
3479	iface = wpa_s->global->dbus;
3480
3481	/* Do nothing if the control interface is not turned on */
3482	if (iface == NULL || !wpa_s->dbus_new_path)
3483		return;
3484
3485	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3486		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
3487		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
3488
3489	msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface,
3490				      sig_name);
3491	if (msg == NULL)
3492		return;
3493
3494	dbus_message_iter_init_append(msg, &iter);
3495	path = peer_obj_path;
3496	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
3497					    &path))
3498		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
3499	else
3500		dbus_connection_send(iface->con, msg, NULL);
3501
3502	dbus_message_unref(msg);
3503}
3504
3505
3506/**
3507 * wpas_dbus_signal_peer_found - Send a peer found signal
3508 * @wpa_s: %wpa_supplicant network interface data
3509 * @dev_addr: Peer P2P Device Address
3510 *
3511 * Notify listeners about find a p2p peer device found
3512 */
3513void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
3514					const u8 *dev_addr)
3515{
3516	wpas_dbus_signal_peer(wpa_s, dev_addr,
3517			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3518			      "DeviceFound");
3519}
3520
3521/**
3522 * wpas_dbus_signal_peer_lost - Send a peer lost signal
3523 * @wpa_s: %wpa_supplicant network interface data
3524 * @dev_addr: Peer P2P Device Address
3525 *
3526 * Notify listeners about lost a p2p peer device
3527 */
3528void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
3529				       const u8 *dev_addr)
3530{
3531	wpas_dbus_signal_peer(wpa_s, dev_addr,
3532			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3533			      "DeviceLost");
3534}
3535
3536/**
3537 * wpas_dbus_register_peer - Register a discovered peer object with dbus
3538 * @wpa_s: wpa_supplicant interface structure
3539 * @dev_addr: P2P Device Address of the peer
3540 * Returns: 0 on success, -1 on failure
3541 *
3542 * Registers network representing object with dbus
3543 */
3544int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
3545{
3546	struct wpas_dbus_priv *ctrl_iface;
3547	struct wpa_dbus_object_desc *obj_desc;
3548	struct peer_handler_args *arg;
3549	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3550
3551	/* Do nothing if the control interface is not turned on */
3552	if (wpa_s == NULL || wpa_s->global == NULL)
3553		return 0;
3554
3555	ctrl_iface = wpa_s->global->dbus;
3556	if (ctrl_iface == NULL)
3557		return 0;
3558
3559	wpa_s = wpa_s->parent->parent;
3560	if (!wpa_s->dbus_new_path)
3561		return 0;
3562
3563	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3564		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
3565		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
3566
3567	wpa_printf(MSG_INFO, "dbus: Register peer object '%s'",
3568		   peer_obj_path);
3569	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3570	if (!obj_desc) {
3571		wpa_printf(MSG_ERROR,
3572			   "Not enough memory to create object description");
3573		goto err;
3574	}
3575
3576	/* allocate memory for handlers arguments */
3577	arg = os_zalloc(sizeof(struct peer_handler_args));
3578	if (!arg) {
3579		wpa_printf(MSG_ERROR,
3580			   "Not enough memory to create arguments for method");
3581		goto err;
3582	}
3583
3584	arg->wpa_s = wpa_s;
3585	os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN);
3586
3587	wpas_dbus_register(obj_desc, arg, wpa_dbus_free,
3588			   NULL,
3589			   wpas_dbus_p2p_peer_properties,
3590			   wpas_dbus_p2p_peer_signals);
3591
3592	if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path,
3593					       wpa_s->ifname, obj_desc))
3594		goto err;
3595
3596	return 0;
3597
3598err:
3599	free_dbus_object_desc(obj_desc);
3600	return -1;
3601}
3602
3603/**
3604 * wpas_dbus_unregister_peer - Unregister a peer object with dbus
3605 * @wpa_s: wpa_supplicant interface structure
3606 * @dev_addr: p2p device addr
3607 * Returns: 0 on success, -1 on failure
3608 *
3609 * Registers network representing object with dbus
3610 */
3611int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
3612				  const u8 *dev_addr)
3613{
3614	struct wpas_dbus_priv *ctrl_iface;
3615	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3616	int ret;
3617
3618	/* Do nothing if the control interface is not turned on */
3619	if (wpa_s == NULL || wpa_s->global == NULL)
3620		return 0;
3621
3622	wpa_s = wpa_s->parent->parent;
3623	if (!wpa_s->dbus_new_path)
3624		return 0;
3625
3626	ctrl_iface = wpa_s->global->dbus;
3627	if (ctrl_iface == NULL)
3628		return 0;
3629
3630	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3631		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
3632		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
3633
3634	wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'",
3635		   peer_obj_path);
3636	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path);
3637
3638	return ret;
3639}
3640
3641
3642/**
3643 * wpas_dbus_signal_p2p_find_stopped - Send P2P Find stopped signal
3644 * @wpa_s: %wpa_supplicant network interface data
3645 *
3646 * Notify listeners about P2P Find stopped
3647 */
3648void wpas_dbus_signal_p2p_find_stopped(struct wpa_supplicant *wpa_s)
3649{
3650	struct wpas_dbus_priv *iface;
3651	DBusMessage *msg;
3652
3653	iface = wpa_s->global->dbus;
3654
3655	/* Do nothing if the control interface is not turned on */
3656	if (iface == NULL || !wpa_s->dbus_new_path)
3657		return;
3658
3659	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
3660				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3661				      "FindStopped");
3662	if (msg == NULL)
3663		return;
3664
3665	dbus_connection_send(iface->con, msg, NULL);
3666
3667	dbus_message_unref(msg);
3668}
3669
3670
3671/**
3672 * wpas_dbus_signal_peer_groups_changed - Send peer group change property signal
3673 * @wpa_s: %wpa_supplicant network interface data
3674 * @dev_addr: P2P Device Address
3675 *
3676 * Notify listeners about peer Groups property changes.
3677 */
3678void wpas_dbus_signal_peer_groups_changed(struct wpa_supplicant *wpa_s,
3679					  const u8 *dev_addr)
3680{
3681	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3682
3683	if (wpa_s->p2p_mgmt)
3684		wpa_s = wpa_s->parent;
3685
3686	if (!wpa_s->dbus_new_path)
3687		return;
3688	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3689		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
3690		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
3691
3692	wpa_dbus_mark_property_changed(wpa_s->global->dbus, peer_obj_path,
3693				       WPAS_DBUS_NEW_IFACE_P2P_PEER, "Groups");
3694}
3695
3696
3697static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
3698	{ "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
3699	  wpas_dbus_getter_p2p_group_members,
3700	  NULL
3701	},
3702	{ "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o",
3703	  wpas_dbus_getter_p2p_group,
3704	  NULL
3705	},
3706	{ "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
3707	  wpas_dbus_getter_p2p_role,
3708	  NULL
3709	},
3710	{ "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
3711	  wpas_dbus_getter_p2p_group_ssid,
3712	  NULL
3713	},
3714	{ "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
3715	  wpas_dbus_getter_p2p_group_bssid,
3716	  NULL
3717	},
3718	{ "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q",
3719	  wpas_dbus_getter_p2p_group_frequency,
3720	  NULL
3721	},
3722	{ "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
3723	  wpas_dbus_getter_p2p_group_passphrase,
3724	  NULL
3725	},
3726	{ "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
3727	  wpas_dbus_getter_p2p_group_psk,
3728	  NULL
3729	},
3730	{ "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay",
3731	  wpas_dbus_getter_p2p_group_vendor_ext,
3732	  wpas_dbus_setter_p2p_group_vendor_ext
3733	},
3734	{ NULL, NULL, NULL, NULL, NULL }
3735};
3736
3737static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
3738	{ "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
3739	  {
3740		  { "peer", "o", ARG_OUT },
3741		  END_ARGS
3742	  }
3743	},
3744	{ "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
3745	  {
3746		  { "peer", "o", ARG_OUT },
3747		  END_ARGS
3748	  }
3749	},
3750	{ NULL, NULL, { END_ARGS } }
3751};
3752
3753/**
3754 * wpas_dbus_register_p2p_group - Register a p2p group object with dbus
3755 * @wpa_s: wpa_supplicant interface structure
3756 * @ssid: SSID struct
3757 * Returns: 0 on success, -1 on failure
3758 *
3759 * Registers p2p group representing object with dbus
3760 */
3761void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
3762				  struct wpa_ssid *ssid)
3763{
3764	struct wpas_dbus_priv *ctrl_iface;
3765	struct wpa_dbus_object_desc *obj_desc;
3766	char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3767
3768	/* Do nothing if the control interface is not turned on */
3769	if (wpa_s == NULL || wpa_s->global == NULL)
3770		return;
3771
3772	ctrl_iface = wpa_s->global->dbus;
3773	if (ctrl_iface == NULL)
3774		return;
3775
3776	if (wpa_s->dbus_groupobj_path) {
3777		wpa_printf(MSG_INFO, "%s: Group object '%s' already exists",
3778			   __func__, wpa_s->dbus_groupobj_path);
3779		return;
3780	}
3781
3782	if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
3783		return;
3784
3785	wpa_s->dbus_groupobj_path = os_strdup(group_obj_path);
3786	if (wpa_s->dbus_groupobj_path == NULL)
3787		return;
3788
3789	wpa_printf(MSG_INFO, "dbus: Register group object '%s'",
3790		   group_obj_path);
3791	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3792	if (!obj_desc) {
3793		wpa_printf(MSG_ERROR,
3794			   "Not enough memory to create object description");
3795		goto err;
3796	}
3797
3798	wpas_dbus_register(obj_desc, wpa_s, NULL, NULL,
3799			   wpas_dbus_p2p_group_properties,
3800			   wpas_dbus_p2p_group_signals);
3801
3802	if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path,
3803					       wpa_s->ifname, obj_desc))
3804		goto err;
3805
3806	return;
3807
3808err:
3809	if (wpa_s->dbus_groupobj_path) {
3810		os_free(wpa_s->dbus_groupobj_path);
3811		wpa_s->dbus_groupobj_path = NULL;
3812	}
3813
3814	free_dbus_object_desc(obj_desc);
3815}
3816
3817/**
3818 * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus
3819 * @wpa_s: wpa_supplicant interface structure
3820 * @ssid: network name of the p2p group started
3821 */
3822void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
3823				    const struct wpa_ssid *ssid)
3824{
3825	struct wpas_dbus_priv *ctrl_iface;
3826
3827	/* Do nothing if the control interface is not turned on */
3828	if (wpa_s == NULL || wpa_s->global == NULL)
3829		return;
3830
3831	if (wpa_s->p2p_mgmt)
3832		wpa_s = wpa_s->parent;
3833
3834	ctrl_iface = wpa_s->global->dbus;
3835	if (ctrl_iface == NULL)
3836		return;
3837
3838	if (!wpa_s->dbus_groupobj_path) {
3839		wpa_printf(MSG_DEBUG,
3840			   "%s: Group object '%s' already unregistered",
3841			   __func__, wpa_s->dbus_groupobj_path);
3842		return;
3843	}
3844
3845	peer_groups_changed(wpa_s);
3846
3847	wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'",
3848		   wpa_s->dbus_groupobj_path);
3849
3850	wpa_dbus_unregister_object_per_iface(ctrl_iface,
3851					     wpa_s->dbus_groupobj_path);
3852
3853	os_free(wpa_s->dbus_groupobj_path);
3854	wpa_s->dbus_groupobj_path = NULL;
3855}
3856
3857static const struct wpa_dbus_property_desc
3858	wpas_dbus_persistent_group_properties[] = {
3859	{ "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
3860	  wpas_dbus_getter_persistent_group_properties,
3861	  wpas_dbus_setter_persistent_group_properties
3862	},
3863	{ NULL, NULL, NULL, NULL, NULL }
3864};
3865
3866/* No signals intended for persistent group objects */
3867
3868/**
3869 * wpas_dbus_register_persistent_group - Register a configured(saved)
3870 *	persistent group with dbus
3871 * @wpa_s: wpa_supplicant interface structure
3872 * @ssid: persistent group (still represented as a network within wpa)
3873 *	  configuration data
3874 * Returns: 0 on success, -1 on failure
3875 *
3876 * Registers a persistent group representing object with dbus.
3877 */
3878int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
3879					struct wpa_ssid *ssid)
3880{
3881	struct wpas_dbus_priv *ctrl_iface;
3882	struct wpa_dbus_object_desc *obj_desc;
3883	struct network_handler_args *arg;
3884	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3885
3886	/* Do nothing if the control interface is not turned on */
3887	if (wpa_s == NULL || wpa_s->global == NULL)
3888		return 0;
3889	wpa_s = wpa_s->parent->parent;
3890	if (!wpa_s->dbus_new_path)
3891		return 0;
3892
3893	/* Make sure ssid is a persistent group */
3894	if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
3895		return -1; /* should we return w/o complaining? */
3896
3897	if (wpa_s->p2p_mgmt)
3898		wpa_s = wpa_s->parent;
3899
3900	ctrl_iface = wpa_s->global->dbus;
3901	if (ctrl_iface == NULL)
3902		return 0;
3903
3904	/*
3905	 * Intentionally not coming up with different numbering scheme
3906	 * for persistent groups.
3907	 */
3908	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3909		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
3910		    wpa_s->dbus_new_path, ssid->id);
3911
3912	wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'",
3913		   pgrp_obj_path);
3914	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3915	if (!obj_desc) {
3916		wpa_printf(MSG_ERROR,
3917			   "dbus: Not enough memory to create object description");
3918		goto err;
3919	}
3920
3921	/*
3922	 * Reusing the same context structure as that for networks
3923	 * since these are represented using same data structure.
3924	 */
3925	/* allocate memory for handlers arguments */
3926	arg = os_zalloc(sizeof(struct network_handler_args));
3927	if (!arg) {
3928		wpa_printf(MSG_ERROR,
3929			   "dbus: Not enough memory to create arguments for method");
3930		goto err;
3931	}
3932
3933	arg->wpa_s = wpa_s;
3934	arg->ssid = ssid;
3935
3936	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
3937			   wpas_dbus_persistent_group_properties,
3938			   NULL);
3939
3940	if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path,
3941					       wpa_s->ifname, obj_desc))
3942		goto err;
3943
3944	wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id);
3945
3946	return 0;
3947
3948err:
3949	free_dbus_object_desc(obj_desc);
3950	return -1;
3951}
3952
3953
3954/**
3955 * wpas_dbus_unregister_persistent_group - Unregister a persistent_group
3956 *	from dbus
3957 * @wpa_s: wpa_supplicant interface structure
3958 * @nid: network id
3959 * Returns: 0 on success, -1 on failure
3960 *
3961 * Unregisters persistent group representing object from dbus
3962 *
3963 * NOTE: There is a slight issue with the semantics here. While the
3964 * implementation simply means the persistent group is unloaded from memory,
3965 * it should not get interpreted as the group is actually being erased/removed
3966 * from persistent storage as well.
3967 */
3968int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
3969					  int nid)
3970{
3971	struct wpas_dbus_priv *ctrl_iface;
3972	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3973	int ret;
3974
3975	/* Do nothing if the control interface is not turned on */
3976	if (wpa_s == NULL || wpa_s->global == NULL)
3977		return 0;
3978
3979	wpa_s = wpa_s->parent->parent;
3980
3981	ctrl_iface = wpa_s->global->dbus;
3982	if (ctrl_iface == NULL || !wpa_s->dbus_new_path)
3983		return 0;
3984
3985	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3986		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
3987		    wpa_s->dbus_new_path, nid);
3988
3989	wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'",
3990		   pgrp_obj_path);
3991	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path);
3992
3993	if (!ret)
3994		wpas_dbus_signal_persistent_group_removed(wpa_s, nid);
3995
3996	return ret;
3997}
3998
3999#endif /* CONFIG_P2P */
4000