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