dbus_new.c revision 252733
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_IES:
1812		prop = "IEs";
1813		break;
1814	default:
1815		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
1816			   __func__, property);
1817		return;
1818	}
1819
1820	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1821		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
1822		    wpa_s->dbus_new_path, id);
1823
1824	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
1825				       WPAS_DBUS_NEW_IFACE_BSS, prop);
1826}
1827
1828
1829/**
1830 * wpas_dbus_signal_debug_level_changed - Signals change of debug param
1831 * @global: wpa_global structure
1832 *
1833 * Sends PropertyChanged signals informing that debug level has changed.
1834 */
1835void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
1836{
1837	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
1838				       WPAS_DBUS_NEW_INTERFACE,
1839				       "DebugLevel");
1840}
1841
1842
1843/**
1844 * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
1845 * @global: wpa_global structure
1846 *
1847 * Sends PropertyChanged signals informing that debug timestamp has changed.
1848 */
1849void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
1850{
1851	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
1852				       WPAS_DBUS_NEW_INTERFACE,
1853				       "DebugTimestamp");
1854}
1855
1856
1857/**
1858 * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
1859 * @global: wpa_global structure
1860 *
1861 * Sends PropertyChanged signals informing that debug show_keys has changed.
1862 */
1863void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
1864{
1865	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
1866				       WPAS_DBUS_NEW_INTERFACE,
1867				       "DebugShowKeys");
1868}
1869
1870
1871static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc,
1872			       void *priv,
1873			       WPADBusArgumentFreeFunction priv_free,
1874			       const struct wpa_dbus_method_desc *methods,
1875			       const struct wpa_dbus_property_desc *properties,
1876			       const struct wpa_dbus_signal_desc *signals)
1877{
1878	int n;
1879
1880	obj_desc->user_data = priv;
1881	obj_desc->user_data_free_func = priv_free;
1882	obj_desc->methods = methods;
1883	obj_desc->properties = properties;
1884	obj_desc->signals = signals;
1885
1886	for (n = 0; properties && properties->dbus_property; properties++)
1887		n++;
1888
1889	obj_desc->prop_changed_flags = os_zalloc(n);
1890	if (!obj_desc->prop_changed_flags)
1891		wpa_printf(MSG_DEBUG, "dbus: %s: can't register handlers",
1892			   __func__);
1893}
1894
1895
1896static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
1897	{ "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
1898	  (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
1899	  {
1900		  { "args", "a{sv}", ARG_IN },
1901		  { "path", "o", ARG_OUT },
1902		  END_ARGS
1903	  }
1904	},
1905	{ "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
1906	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
1907	  {
1908		  { "path", "o", ARG_IN },
1909		  END_ARGS
1910	  }
1911	},
1912	{ "GetInterface", WPAS_DBUS_NEW_INTERFACE,
1913	  (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
1914	  {
1915		  { "ifname", "s", ARG_IN },
1916		  { "path", "o", ARG_OUT },
1917		  END_ARGS
1918	  }
1919	},
1920#ifdef CONFIG_AUTOSCAN
1921	{ "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
1922	  (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
1923	  {
1924		  { "arg", "s", ARG_IN },
1925		  END_ARGS
1926	  }
1927	},
1928#endif /* CONFIG_AUTOSCAN */
1929	{ NULL, NULL, NULL, { END_ARGS } }
1930};
1931
1932static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
1933	{ "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
1934	  wpas_dbus_getter_debug_level,
1935	  wpas_dbus_setter_debug_level
1936	},
1937	{ "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
1938	  wpas_dbus_getter_debug_timestamp,
1939	  wpas_dbus_setter_debug_timestamp
1940	},
1941	{ "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
1942	  wpas_dbus_getter_debug_show_keys,
1943	  wpas_dbus_setter_debug_show_keys
1944	},
1945	{ "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
1946	  wpas_dbus_getter_interfaces,
1947	  NULL
1948	},
1949	{ "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
1950	  wpas_dbus_getter_eap_methods,
1951	  NULL
1952	},
1953	{ "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
1954	  wpas_dbus_getter_global_capabilities,
1955	  NULL
1956	},
1957	{ NULL, NULL, NULL, NULL, NULL }
1958};
1959
1960static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
1961	{ "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE,
1962	  {
1963		  { "path", "o", ARG_OUT },
1964		  { "properties", "a{sv}", ARG_OUT },
1965		  END_ARGS
1966	  }
1967	},
1968	{ "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE,
1969	  {
1970		  { "path", "o", ARG_OUT },
1971		  END_ARGS
1972	  }
1973	},
1974	{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
1975	  {
1976		  { "path", "o", ARG_OUT },
1977		  { "field", "s", ARG_OUT },
1978		  { "text", "s", ARG_OUT },
1979		  END_ARGS
1980	  }
1981	},
1982	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
1983	{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
1984	  {
1985		  { "properties", "a{sv}", ARG_OUT },
1986		  END_ARGS
1987	  }
1988	},
1989	{ NULL, NULL, { END_ARGS } }
1990};
1991
1992
1993/**
1994 * wpas_dbus_ctrl_iface_init - Initialize dbus control interface
1995 * @global: Pointer to global data from wpa_supplicant_init()
1996 * Returns: 0 on success or -1 on failure
1997 *
1998 * Initialize the dbus control interface for wpa_supplicantand and start
1999 * receiving commands from external programs over the bus.
2000 */
2001int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
2002{
2003	struct wpa_dbus_object_desc *obj_desc;
2004	int ret;
2005
2006	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
2007	if (!obj_desc) {
2008		wpa_printf(MSG_ERROR, "Not enough memory "
2009			   "to create object description");
2010		return -1;
2011	}
2012
2013	wpas_dbus_register(obj_desc, priv->global, NULL,
2014			   wpas_dbus_global_methods,
2015			   wpas_dbus_global_properties,
2016			   wpas_dbus_global_signals);
2017
2018	wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'",
2019		   WPAS_DBUS_NEW_PATH);
2020	ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
2021				       WPAS_DBUS_NEW_SERVICE,
2022				       obj_desc);
2023	if (ret < 0)
2024		free_dbus_object_desc(obj_desc);
2025	else
2026		priv->dbus_new_initialized = 1;
2027
2028	return ret;
2029}
2030
2031
2032/**
2033 * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
2034 * wpa_supplicant
2035 * @iface: Pointer to dbus private data from wpas_dbus_init()
2036 *
2037 * Deinitialize the dbus control interface that was initialized with
2038 * wpas_dbus_ctrl_iface_init().
2039 */
2040void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface)
2041{
2042	if (!iface->dbus_new_initialized)
2043		return;
2044	wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'",
2045		   WPAS_DBUS_NEW_PATH);
2046	dbus_connection_unregister_object_path(iface->con,
2047					       WPAS_DBUS_NEW_PATH);
2048}
2049
2050
2051static void wpa_dbus_free(void *ptr)
2052{
2053	os_free(ptr);
2054}
2055
2056
2057static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
2058	{ "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
2059	  wpas_dbus_getter_network_properties,
2060	  wpas_dbus_setter_network_properties
2061	},
2062	{ "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
2063	  wpas_dbus_getter_enabled,
2064	  wpas_dbus_setter_enabled
2065	},
2066	{ NULL, NULL, NULL, NULL, NULL }
2067};
2068
2069
2070static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = {
2071	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2072	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
2073	  {
2074		  { "properties", "a{sv}", ARG_OUT },
2075		  END_ARGS
2076	  }
2077	},
2078	{ NULL, NULL, { END_ARGS } }
2079};
2080
2081
2082/**
2083 * wpas_dbus_register_network - Register a configured network with dbus
2084 * @wpa_s: wpa_supplicant interface structure
2085 * @ssid: network configuration data
2086 * Returns: 0 on success, -1 on failure
2087 *
2088 * Registers network representing object with dbus
2089 */
2090int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
2091			       struct wpa_ssid *ssid)
2092{
2093	struct wpas_dbus_priv *ctrl_iface;
2094	struct wpa_dbus_object_desc *obj_desc;
2095	struct network_handler_args *arg;
2096	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2097
2098#ifdef CONFIG_P2P
2099	/*
2100	 * If it is a persistent group register it as such.
2101	 * This is to handle cases where an interface is being initialized
2102	 * with a list of networks read from config.
2103	 */
2104	if (network_is_persistent_group(ssid))
2105		return wpas_dbus_register_persistent_group(wpa_s, ssid);
2106#endif /* CONFIG_P2P */
2107
2108	/* Do nothing if the control interface is not turned on */
2109	if (wpa_s == NULL || wpa_s->global == NULL)
2110		return 0;
2111	ctrl_iface = wpa_s->global->dbus;
2112	if (ctrl_iface == NULL)
2113		return 0;
2114
2115	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2116		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
2117		    wpa_s->dbus_new_path, ssid->id);
2118
2119	wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'",
2120		   net_obj_path);
2121	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
2122	if (!obj_desc) {
2123		wpa_printf(MSG_ERROR, "Not enough memory "
2124			   "to create object description");
2125		goto err;
2126	}
2127
2128	/* allocate memory for handlers arguments */
2129	arg = os_zalloc(sizeof(struct network_handler_args));
2130	if (!arg) {
2131		wpa_printf(MSG_ERROR, "Not enough memory "
2132			   "to create arguments for method");
2133		goto err;
2134	}
2135
2136	arg->wpa_s = wpa_s;
2137	arg->ssid = ssid;
2138
2139	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
2140			   wpas_dbus_network_properties,
2141			   wpas_dbus_network_signals);
2142
2143	if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path,
2144					       wpa_s->ifname, obj_desc))
2145		goto err;
2146
2147	wpas_dbus_signal_network_added(wpa_s, ssid->id);
2148
2149	return 0;
2150
2151err:
2152	free_dbus_object_desc(obj_desc);
2153	return -1;
2154}
2155
2156
2157/**
2158 * wpas_dbus_unregister_network - Unregister a configured network from dbus
2159 * @wpa_s: wpa_supplicant interface structure
2160 * @nid: network id
2161 * Returns: 0 on success, -1 on failure
2162 *
2163 * Unregisters network representing object from dbus
2164 */
2165int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
2166{
2167	struct wpas_dbus_priv *ctrl_iface;
2168	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2169	int ret;
2170#ifdef CONFIG_P2P
2171	struct wpa_ssid *ssid;
2172
2173	ssid = wpa_config_get_network(wpa_s->conf, nid);
2174
2175	/* If it is a persistent group unregister it as such */
2176	if (ssid && network_is_persistent_group(ssid))
2177		return wpas_dbus_unregister_persistent_group(wpa_s, nid);
2178#endif /* CONFIG_P2P */
2179
2180	/* Do nothing if the control interface is not turned on */
2181	if (wpa_s->global == NULL || wpa_s->dbus_new_path == NULL)
2182		return 0;
2183	ctrl_iface = wpa_s->global->dbus;
2184	if (ctrl_iface == NULL)
2185		return 0;
2186
2187	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2188		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
2189		    wpa_s->dbus_new_path, nid);
2190
2191	wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'",
2192		   net_obj_path);
2193	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path);
2194
2195	if (!ret)
2196		wpas_dbus_signal_network_removed(wpa_s, nid);
2197
2198	return ret;
2199}
2200
2201
2202static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
2203	{ "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
2204	  wpas_dbus_getter_bss_ssid,
2205	  NULL
2206	},
2207	{ "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
2208	  wpas_dbus_getter_bss_bssid,
2209	  NULL
2210	},
2211	{ "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
2212	  wpas_dbus_getter_bss_privacy,
2213	  NULL
2214	},
2215	{ "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
2216	  wpas_dbus_getter_bss_mode,
2217	  NULL
2218	},
2219	{ "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
2220	  wpas_dbus_getter_bss_signal,
2221	  NULL
2222	},
2223	{ "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
2224	  wpas_dbus_getter_bss_frequency,
2225	  NULL
2226	},
2227	{ "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
2228	  wpas_dbus_getter_bss_rates,
2229	  NULL
2230	},
2231	{ "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
2232	  wpas_dbus_getter_bss_wpa,
2233	  NULL
2234	},
2235	{ "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
2236	  wpas_dbus_getter_bss_rsn,
2237	  NULL
2238	},
2239	{ "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
2240	  wpas_dbus_getter_bss_wps,
2241	  NULL
2242	},
2243	{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
2244	  wpas_dbus_getter_bss_ies,
2245	  NULL
2246	},
2247	{ NULL, NULL, NULL, NULL, NULL }
2248};
2249
2250
2251static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = {
2252	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2253	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS,
2254	  {
2255		  { "properties", "a{sv}", ARG_OUT },
2256		  END_ARGS
2257	  }
2258	},
2259	{ NULL, NULL, { END_ARGS } }
2260};
2261
2262
2263/**
2264 * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus
2265 * @wpa_s: wpa_supplicant interface structure
2266 * @bssid: scanned network bssid
2267 * @id: unique BSS identifier
2268 * Returns: 0 on success, -1 on failure
2269 *
2270 * Unregisters BSS representing object from dbus
2271 */
2272int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
2273			     u8 bssid[ETH_ALEN], unsigned int id)
2274{
2275	struct wpas_dbus_priv *ctrl_iface;
2276	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2277
2278	/* Do nothing if the control interface is not turned on */
2279	if (wpa_s == NULL || wpa_s->global == NULL)
2280		return 0;
2281	ctrl_iface = wpa_s->global->dbus;
2282	if (ctrl_iface == NULL)
2283		return 0;
2284
2285	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2286		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
2287		    wpa_s->dbus_new_path, id);
2288
2289	wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'",
2290		   bss_obj_path);
2291	if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) {
2292		wpa_printf(MSG_ERROR, "dbus: Cannot unregister BSS object %s",
2293			   bss_obj_path);
2294		return -1;
2295	}
2296
2297	wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path);
2298	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
2299
2300	return 0;
2301}
2302
2303
2304/**
2305 * wpas_dbus_register_bss - Register a scanned BSS with dbus
2306 * @wpa_s: wpa_supplicant interface structure
2307 * @bssid: scanned network bssid
2308 * @id: unique BSS identifier
2309 * Returns: 0 on success, -1 on failure
2310 *
2311 * Registers BSS representing object with dbus
2312 */
2313int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
2314			   u8 bssid[ETH_ALEN], unsigned int id)
2315{
2316	struct wpas_dbus_priv *ctrl_iface;
2317	struct wpa_dbus_object_desc *obj_desc;
2318	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
2319	struct bss_handler_args *arg;
2320
2321	/* Do nothing if the control interface is not turned on */
2322	if (wpa_s == NULL || wpa_s->global == NULL)
2323		return 0;
2324	ctrl_iface = wpa_s->global->dbus;
2325	if (ctrl_iface == NULL)
2326		return 0;
2327
2328	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2329		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
2330		    wpa_s->dbus_new_path, id);
2331
2332	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
2333	if (!obj_desc) {
2334		wpa_printf(MSG_ERROR, "Not enough memory "
2335			   "to create object description");
2336		goto err;
2337	}
2338
2339	arg = os_zalloc(sizeof(struct bss_handler_args));
2340	if (!arg) {
2341		wpa_printf(MSG_ERROR, "Not enough memory "
2342			   "to create arguments for handler");
2343		goto err;
2344	}
2345	arg->wpa_s = wpa_s;
2346	arg->id = id;
2347
2348	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
2349			   wpas_dbus_bss_properties,
2350			   wpas_dbus_bss_signals);
2351
2352	wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'",
2353		   bss_obj_path);
2354	if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path,
2355					       wpa_s->ifname, obj_desc)) {
2356		wpa_printf(MSG_ERROR,
2357			   "Cannot register BSSID dbus object %s.",
2358			   bss_obj_path);
2359		goto err;
2360	}
2361
2362	wpas_dbus_signal_bss_added(wpa_s, bss_obj_path);
2363	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
2364
2365	return 0;
2366
2367err:
2368	free_dbus_object_desc(obj_desc);
2369	return -1;
2370}
2371
2372
2373static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
2374	{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
2375	  (WPADBusMethodHandler) &wpas_dbus_handler_scan,
2376	  {
2377		  { "args", "a{sv}", ARG_IN },
2378		  END_ARGS
2379	  }
2380	},
2381	{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
2382	  (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
2383	  {
2384		  END_ARGS
2385	  }
2386	},
2387	{ "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
2388	  (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
2389	  {
2390		  { "args", "a{sv}", ARG_IN },
2391		  { "path", "o", ARG_OUT },
2392		  END_ARGS
2393	  }
2394	},
2395	{ "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
2396	  (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
2397	  {
2398		  END_ARGS
2399	  }
2400	},
2401	{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
2402	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
2403	  {
2404		  { "path", "o", ARG_IN },
2405		  END_ARGS
2406	  }
2407	},
2408	{ "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
2409	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks,
2410	  {
2411		  END_ARGS
2412	  }
2413	},
2414	{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
2415	  (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
2416	  {
2417		  { "path", "o", ARG_IN },
2418		  END_ARGS
2419	  }
2420	},
2421	{ "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
2422	  (WPADBusMethodHandler) &wpas_dbus_handler_network_reply,
2423	  {
2424		  { "path", "o", ARG_IN },
2425		  { "field", "s", ARG_IN },
2426		  { "value", "s", ARG_IN },
2427		  END_ARGS
2428	  }
2429	},
2430	{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
2431	  (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
2432	  {
2433		  { "name", "s", ARG_IN },
2434		  { "data", "ay", ARG_IN },
2435		  END_ARGS
2436	  }
2437	},
2438	{ "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
2439	  (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
2440	  {
2441		  { "name", "s", ARG_IN },
2442		  { "data", "ay", ARG_OUT },
2443		  END_ARGS
2444	  }
2445	},
2446	{ "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
2447	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
2448	  {
2449		  { "name", "s", ARG_IN },
2450		  END_ARGS
2451	  }
2452	},
2453#ifdef CONFIG_WPS
2454	{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
2455	  (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
2456	  {
2457		  { "args", "a{sv}", ARG_IN },
2458		  { "output", "a{sv}", ARG_OUT },
2459		  END_ARGS
2460	  }
2461	},
2462#endif /* CONFIG_WPS */
2463#ifdef CONFIG_P2P
2464	{ "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2465	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
2466	  {
2467		  { "args", "a{sv}", ARG_IN },
2468		  END_ARGS
2469	  }
2470	},
2471	{ "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2472	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
2473	  {
2474		  END_ARGS
2475	  }
2476	},
2477	{ "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2478	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
2479	  {
2480		  { "timeout", "i", ARG_IN },
2481		  END_ARGS
2482	  }
2483	},
2484	{ "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2485	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
2486	  {
2487		  { "args", "a{sv}", ARG_IN },
2488		  END_ARGS
2489	  }
2490	},
2491	{ "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2492	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
2493	  {
2494		  { "args", "a{sv}", ARG_IN },
2495		  END_ARGS
2496	  }
2497	},
2498	{ "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2499	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
2500	  {
2501		  { "peer", "o", ARG_IN },
2502		  { "config_method", "s", ARG_IN },
2503		  END_ARGS
2504	  }
2505	},
2506	{ "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2507	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
2508	  {
2509		  { "args", "a{sv}", ARG_IN },
2510		  { "generated_pin", "s", ARG_OUT },
2511		  END_ARGS
2512	  }
2513	},
2514	{ "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2515	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
2516	  {
2517		  { "args", "a{sv}", ARG_IN },
2518		  END_ARGS
2519	  }
2520	},
2521	{ "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2522	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
2523	  {
2524		  { "args", "a{sv}", ARG_IN },
2525		  END_ARGS
2526	  }
2527	},
2528	{ "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2529	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
2530	  {
2531		  END_ARGS
2532	  }
2533	},
2534	{ "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2535	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
2536	  {
2537		  { "peer", "o", ARG_IN },
2538		  END_ARGS
2539	  }
2540	},
2541	{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2542	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
2543	  {
2544		  END_ARGS
2545	  }
2546	},
2547	{ "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2548	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
2549	  {
2550		  { "args", "a{sv}", ARG_IN },
2551		  END_ARGS
2552	  }
2553	},
2554	{ "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2555	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
2556	  {
2557		  { "args", "a{sv}", ARG_IN },
2558		  END_ARGS
2559	  }
2560	},
2561	{ "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2562	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
2563	  {
2564		  END_ARGS
2565	  }
2566	},
2567	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2568	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
2569	  {
2570		  { "args", "a{sv}", ARG_IN },
2571		  END_ARGS
2572	  }
2573	},
2574	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2575	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
2576	  {
2577		  { "args", "a{sv}", ARG_IN },
2578		  END_ARGS
2579	  }
2580	},
2581	{ "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2582	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
2583	  {
2584		  { "args", "t", ARG_IN },
2585		  END_ARGS
2586	  }
2587	},
2588	{ "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2589	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
2590	  {
2591		  END_ARGS
2592	  }
2593	},
2594	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2595	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
2596	  {
2597		  { "arg", "i", ARG_IN },
2598		  END_ARGS
2599	  }
2600	},
2601	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2602	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
2603	  {
2604		  { "arg", "i", ARG_IN },
2605		  END_ARGS
2606	  }
2607	},
2608	{ "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2609	  (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group,
2610	  {
2611		  { "args", "a{sv}", ARG_IN },
2612		  { "path", "o", ARG_OUT },
2613		  END_ARGS
2614	  }
2615	},
2616	{ "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2617	  (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group,
2618	  {
2619		  { "path", "o", ARG_IN },
2620		  END_ARGS
2621	  }
2622	},
2623	{ "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2624	  (WPADBusMethodHandler)
2625	  wpas_dbus_handler_remove_all_persistent_groups,
2626	  {
2627		  END_ARGS
2628	  }
2629	},
2630#endif /* CONFIG_P2P */
2631	{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
2632	  (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
2633	  {
2634		  { "age", "u", ARG_IN },
2635		  END_ARGS
2636	  }
2637	},
2638#ifdef CONFIG_AP
2639	{ "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
2640	  (WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq,
2641	  {
2642		  END_ARGS
2643	  }
2644	},
2645	{ "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
2646	  (WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq,
2647	  {
2648		  END_ARGS
2649	  }
2650	},
2651#endif /* CONFIG_AP */
2652	{ NULL, NULL, NULL, { END_ARGS } }
2653};
2654
2655static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
2656	{ "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
2657	  wpas_dbus_getter_capabilities,
2658	  NULL
2659	},
2660	{ "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2661	  wpas_dbus_getter_state,
2662	  NULL
2663	},
2664	{ "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
2665	  wpas_dbus_getter_scanning,
2666	  NULL
2667	},
2668	{ "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
2669	  wpas_dbus_getter_ap_scan,
2670	  wpas_dbus_setter_ap_scan
2671	},
2672	{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
2673	  wpas_dbus_getter_bss_expire_age,
2674	  wpas_dbus_setter_bss_expire_age
2675	},
2676	{ "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
2677	  wpas_dbus_getter_bss_expire_count,
2678	  wpas_dbus_setter_bss_expire_count
2679	},
2680	{ "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2681	  wpas_dbus_getter_country,
2682	  wpas_dbus_setter_country
2683	},
2684	{ "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2685	  wpas_dbus_getter_ifname,
2686	  NULL
2687	},
2688	{ "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2689	  wpas_dbus_getter_driver,
2690	  NULL
2691	},
2692	{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2693	  wpas_dbus_getter_bridge_ifname,
2694	  NULL
2695	},
2696	{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
2697	  wpas_dbus_getter_current_bss,
2698	  NULL
2699	},
2700	{ "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
2701	  wpas_dbus_getter_current_network,
2702	  NULL
2703	},
2704	{ "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
2705	  wpas_dbus_getter_current_auth_mode,
2706	  NULL
2707	},
2708	{ "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
2709	  wpas_dbus_getter_blobs,
2710	  NULL
2711	},
2712	{ "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
2713	  wpas_dbus_getter_bsss,
2714	  NULL
2715	},
2716	{ "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
2717	  wpas_dbus_getter_networks,
2718	  NULL
2719	},
2720	{ "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
2721	  wpas_dbus_getter_fast_reauth,
2722	  wpas_dbus_setter_fast_reauth
2723	},
2724	{ "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
2725	  wpas_dbus_getter_scan_interval,
2726	  wpas_dbus_setter_scan_interval
2727	},
2728#ifdef CONFIG_WPS
2729	{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
2730	  wpas_dbus_getter_process_credentials,
2731	  wpas_dbus_setter_process_credentials
2732	},
2733#endif /* CONFIG_WPS */
2734#ifdef CONFIG_P2P
2735	{ "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
2736	  wpas_dbus_getter_p2p_device_config,
2737	  wpas_dbus_setter_p2p_device_config
2738	},
2739	{ "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
2740	  wpas_dbus_getter_p2p_peers,
2741	  NULL
2742	},
2743	{ "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
2744	  wpas_dbus_getter_p2p_role,
2745	  NULL
2746	},
2747	{ "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
2748	  wpas_dbus_getter_p2p_group,
2749	  NULL
2750	},
2751	{ "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
2752	  wpas_dbus_getter_p2p_peergo,
2753	  NULL
2754	},
2755	{ "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
2756	  wpas_dbus_getter_persistent_groups,
2757	  NULL
2758	},
2759#endif /* CONFIG_P2P */
2760	{ "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
2761	  wpas_dbus_getter_disconnect_reason,
2762	  NULL
2763	},
2764	{ NULL, NULL, NULL, NULL, NULL }
2765};
2766
2767static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
2768	{ "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
2769	  {
2770		  { "success", "b", ARG_OUT },
2771		  END_ARGS
2772	  }
2773	},
2774	{ "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
2775	  {
2776		  { "path", "o", ARG_OUT },
2777		  { "properties", "a{sv}", ARG_OUT },
2778		  END_ARGS
2779	  }
2780	},
2781	{ "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
2782	  {
2783		  { "path", "o", ARG_OUT },
2784		  END_ARGS
2785	  }
2786	},
2787	{ "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
2788	  {
2789		  { "name", "s", ARG_OUT },
2790		  END_ARGS
2791	  }
2792	},
2793	{ "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
2794	  {
2795		  { "name", "s", ARG_OUT },
2796		  END_ARGS
2797	  }
2798	},
2799	{ "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
2800	  {
2801		  { "path", "o", ARG_OUT },
2802		  { "properties", "a{sv}", ARG_OUT },
2803		  END_ARGS
2804	  }
2805	},
2806	{ "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
2807	  {
2808		  { "path", "o", ARG_OUT },
2809		  END_ARGS
2810	  }
2811	},
2812	{ "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE,
2813	  {
2814		  { "path", "o", ARG_OUT },
2815		  END_ARGS
2816	  }
2817	},
2818	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2819	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
2820	  {
2821		  { "properties", "a{sv}", ARG_OUT },
2822		  END_ARGS
2823	  }
2824	},
2825#ifdef CONFIG_WPS
2826	{ "Event", WPAS_DBUS_NEW_IFACE_WPS,
2827	  {
2828		  { "name", "s", ARG_OUT },
2829		  { "args", "a{sv}", ARG_OUT },
2830		  END_ARGS
2831	  }
2832	},
2833	{ "Credentials", WPAS_DBUS_NEW_IFACE_WPS,
2834	  {
2835		  { "credentials", "a{sv}", ARG_OUT },
2836		  END_ARGS
2837	  }
2838	},
2839	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
2840	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
2841	  {
2842		  { "properties", "a{sv}", ARG_OUT },
2843		  END_ARGS
2844	  }
2845	},
2846#endif /* CONFIG_WPS */
2847#ifdef CONFIG_P2P
2848	{ "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2849	  {
2850		  { "states", "a{ss}", ARG_OUT },
2851		  END_ARGS
2852	  }
2853	},
2854	{ "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2855	  {
2856		  { "path", "o", ARG_OUT },
2857		  { "properties", "a{sv}", ARG_OUT },
2858		  END_ARGS
2859	  }
2860	},
2861	{ "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2862	  {
2863		  { "path", "o", ARG_OUT },
2864		  END_ARGS
2865	  }
2866	},
2867	{ "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2868	  {
2869		  { "peer_object", "o", ARG_OUT },
2870		  { "pin", "s", ARG_OUT },
2871		  END_ARGS
2872	  }
2873	},
2874	{ "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2875	  {
2876		  { "peer_object", "o", ARG_OUT },
2877		  { "pin", "s", ARG_OUT },
2878		  END_ARGS
2879	  }
2880	},
2881	{ "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2882	  {
2883		  { "peer_object", "o", ARG_OUT },
2884		  END_ARGS
2885	  }
2886	},
2887	{ "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2888	  {
2889		  { "peer_object", "o", ARG_OUT },
2890		  END_ARGS
2891	  }
2892	},
2893	{ "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2894	  {
2895		  { "peer_object", "o", ARG_OUT },
2896		  END_ARGS
2897	  }
2898	},
2899	{ "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2900	  {
2901		  { "peer_object", "o", ARG_OUT },
2902		  END_ARGS
2903	  }
2904	},
2905	{ "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2906	  {
2907		  { "peer_object", "o", ARG_OUT },
2908		  { "status", "i", ARG_OUT },
2909		  END_ARGS
2910	  }
2911	},
2912	{ "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2913	  {
2914		  { "properties", "a{sv}", ARG_OUT },
2915		  END_ARGS
2916	  }
2917	},
2918	{ "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2919	  {
2920		  END_ARGS
2921	  }
2922	},
2923	{ "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2924	  {
2925		  { "status", "i", ARG_OUT },
2926		  END_ARGS
2927	  }
2928	},
2929	{ "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2930	  {
2931		  { "path", "o", ARG_OUT },
2932		  { "dev_passwd_id", "i", ARG_OUT },
2933		  END_ARGS
2934	  }
2935	},
2936	{ "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2937	  {
2938		  { "invite_result", "a{sv}", ARG_OUT },
2939		  END_ARGS
2940	  }
2941	},
2942	{ "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2943	  {
2944		  { "ifname", "s", ARG_OUT },
2945		  { "role", "s", ARG_OUT },
2946		  END_ARGS
2947	  }
2948	},
2949	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2950	  {
2951		  { "sd_request", "a{sv}", ARG_OUT },
2952		  END_ARGS
2953	  }
2954	},
2955	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2956	  {
2957		  { "sd_response", "a{sv}", ARG_OUT },
2958		  END_ARGS
2959	  }
2960	},
2961	{ "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2962	  {
2963		  { "path", "o", ARG_OUT },
2964		  { "properties", "a{sv}", ARG_OUT },
2965		  END_ARGS
2966	  }
2967	},
2968	{ "PersistentGroupRemoved", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2969	  {
2970		  { "path", "o", ARG_OUT },
2971		  END_ARGS
2972	  }
2973	},
2974	{ "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
2975	  {
2976		  { "name", "s", ARG_OUT },
2977		  { "args", "a{sv}", ARG_OUT },
2978		  END_ARGS
2979	  }
2980	},
2981#endif /* CONFIG_P2P */
2982#ifdef CONFIG_AP
2983	{ "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
2984	  {
2985		  { "args", "a{sv}", ARG_OUT },
2986		  END_ARGS
2987	  }
2988	},
2989#endif /* CONFIG_AP */
2990	{ "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
2991	  {
2992		  { "certification", "a{sv}", ARG_OUT },
2993		  END_ARGS
2994	  }
2995	},
2996	{ "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE,
2997	  {
2998		  { "status", "s", ARG_OUT },
2999		  { "parameter", "s", ARG_OUT },
3000		  END_ARGS
3001	  }
3002	},
3003	{ NULL, NULL, { END_ARGS } }
3004};
3005
3006
3007int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
3008{
3009
3010	struct wpa_dbus_object_desc *obj_desc = NULL;
3011	struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
3012	int next;
3013
3014	/* Do nothing if the control interface is not turned on */
3015	if (ctrl_iface == NULL)
3016		return 0;
3017
3018	/* Create and set the interface's object path */
3019	wpa_s->dbus_new_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3020	if (wpa_s->dbus_new_path == NULL)
3021		return -1;
3022	next = ctrl_iface->next_objid++;
3023	os_snprintf(wpa_s->dbus_new_path, WPAS_DBUS_OBJECT_PATH_MAX,
3024		    WPAS_DBUS_NEW_PATH_INTERFACES "/%u",
3025		    next);
3026
3027	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3028	if (!obj_desc) {
3029		wpa_printf(MSG_ERROR, "Not enough memory "
3030			   "to create object description");
3031		goto err;
3032	}
3033
3034	wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
3035			   wpas_dbus_interface_properties,
3036			   wpas_dbus_interface_signals);
3037
3038	wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
3039		   wpa_s->dbus_new_path);
3040	if (wpa_dbus_register_object_per_iface(ctrl_iface,
3041					       wpa_s->dbus_new_path,
3042					       wpa_s->ifname, obj_desc))
3043		goto err;
3044
3045	wpas_dbus_signal_interface_added(wpa_s);
3046
3047	return 0;
3048
3049err:
3050	os_free(wpa_s->dbus_new_path);
3051	wpa_s->dbus_new_path = NULL;
3052	free_dbus_object_desc(obj_desc);
3053	return -1;
3054}
3055
3056
3057int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
3058{
3059	struct wpas_dbus_priv *ctrl_iface;
3060
3061	/* Do nothing if the control interface is not turned on */
3062	if (wpa_s == NULL || wpa_s->global == NULL)
3063		return 0;
3064	ctrl_iface = wpa_s->global->dbus;
3065	if (ctrl_iface == NULL)
3066		return 0;
3067
3068	wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
3069		   wpa_s->dbus_new_path);
3070
3071#ifdef CONFIG_AP
3072	if (wpa_s->preq_notify_peer) {
3073		wpas_dbus_unsubscribe_noc(ctrl_iface);
3074		os_free(wpa_s->preq_notify_peer);
3075		wpa_s->preq_notify_peer = NULL;
3076	}
3077#endif /* CONFIG_AP */
3078
3079	if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
3080						 wpa_s->dbus_new_path))
3081		return -1;
3082
3083	wpas_dbus_signal_interface_removed(wpa_s);
3084
3085	os_free(wpa_s->dbus_new_path);
3086	wpa_s->dbus_new_path = NULL;
3087
3088	return 0;
3089}
3090
3091#ifdef CONFIG_P2P
3092
3093static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
3094	{ "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
3095	  wpas_dbus_getter_p2p_peer_device_name,
3096	  NULL
3097	},
3098	{ "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
3099	  wpas_dbus_getter_p2p_peer_primary_device_type,
3100	  NULL
3101	},
3102	{ "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q",
3103	  wpas_dbus_getter_p2p_peer_config_method,
3104	  NULL
3105	},
3106	{ "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i",
3107	  wpas_dbus_getter_p2p_peer_level,
3108	  NULL
3109	},
3110	{ "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
3111	  wpas_dbus_getter_p2p_peer_device_capability,
3112	  NULL
3113	},
3114	{ "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
3115	  wpas_dbus_getter_p2p_peer_group_capability,
3116	  NULL
3117	},
3118	{ "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
3119	  wpas_dbus_getter_p2p_peer_secondary_device_types,
3120	  NULL
3121	},
3122	{ "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
3123	  wpas_dbus_getter_p2p_peer_vendor_extension,
3124	  NULL
3125	},
3126	{ "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
3127	  wpas_dbus_getter_p2p_peer_ies,
3128	  NULL
3129	},
3130	{ NULL, NULL, NULL, NULL, NULL }
3131};
3132
3133static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
3134
3135	{ NULL, NULL, { END_ARGS } }
3136};
3137
3138/**
3139 * wpas_dbus_signal_peer - Send a peer related event signal
3140 * @wpa_s: %wpa_supplicant network interface data
3141 * @dev: peer device object
3142 * @interface: name of the interface emitting this signal.
3143 *	In case of peer objects, it would be emitted by either
3144 *	the "interface object" or by "peer objects"
3145 * @sig_name: signal name - DeviceFound
3146 *
3147 * Notify listeners about event related with newly found p2p peer device
3148 */
3149static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
3150				  const u8 *dev_addr, const char *interface,
3151				  const char *sig_name)
3152{
3153	struct wpas_dbus_priv *iface;
3154	DBusMessage *msg;
3155	DBusMessageIter iter;
3156	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
3157
3158	iface = wpa_s->global->dbus;
3159
3160	/* Do nothing if the control interface is not turned on */
3161	if (iface == NULL)
3162		return;
3163
3164	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3165		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
3166		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
3167
3168	msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface,
3169				      sig_name);
3170	if (msg == NULL)
3171		return;
3172
3173	dbus_message_iter_init_append(msg, &iter);
3174	path = peer_obj_path;
3175	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
3176					    &path))
3177		goto err;
3178
3179	dbus_connection_send(iface->con, msg, NULL);
3180
3181	dbus_message_unref(msg);
3182	return;
3183
3184err:
3185	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
3186	dbus_message_unref(msg);
3187}
3188
3189
3190/**
3191 * wpas_dbus_signal_peer_found - Send a peer found signal
3192 * @wpa_s: %wpa_supplicant network interface data
3193 * @dev: peer device object
3194 *
3195 * Notify listeners about find a p2p peer device found
3196 */
3197void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
3198					const u8 *dev_addr)
3199{
3200	wpas_dbus_signal_peer(wpa_s, dev_addr,
3201			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3202			      "DeviceFound");
3203}
3204
3205/**
3206 * wpas_dbus_signal_peer_lost - Send a peer lost signal
3207 * @wpa_s: %wpa_supplicant network interface data
3208 * @dev: peer device object
3209 *
3210 * Notify listeners about lost a p2p peer device
3211 */
3212void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
3213				       const u8 *dev_addr)
3214{
3215	wpas_dbus_signal_peer(wpa_s, dev_addr,
3216			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
3217			      "DeviceLost");
3218}
3219
3220/**
3221 * wpas_dbus_register_peer - Register a discovered peer object with dbus
3222 * @wpa_s: wpa_supplicant interface structure
3223 * @ssid: network configuration data
3224 * Returns: 0 on success, -1 on failure
3225 *
3226 * Registers network representing object with dbus
3227 */
3228int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
3229{
3230	struct wpas_dbus_priv *ctrl_iface;
3231	struct wpa_dbus_object_desc *obj_desc;
3232	struct peer_handler_args *arg;
3233	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3234
3235	/* Do nothing if the control interface is not turned on */
3236	if (wpa_s == NULL || wpa_s->global == NULL)
3237		return 0;
3238
3239	ctrl_iface = wpa_s->global->dbus;
3240	if (ctrl_iface == NULL)
3241		return 0;
3242
3243	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3244		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
3245		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
3246
3247	wpa_printf(MSG_INFO, "dbus: Register peer object '%s'",
3248		   peer_obj_path);
3249	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3250	if (!obj_desc) {
3251		wpa_printf(MSG_ERROR, "Not enough memory "
3252			   "to create object description");
3253		goto err;
3254	}
3255
3256	/* allocate memory for handlers arguments */
3257	arg = os_zalloc(sizeof(struct peer_handler_args));
3258	if (!arg) {
3259		wpa_printf(MSG_ERROR, "Not enough memory "
3260			   "to create arguments for method");
3261		goto err;
3262	}
3263
3264	arg->wpa_s = wpa_s;
3265	os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN);
3266
3267	wpas_dbus_register(obj_desc, arg, wpa_dbus_free,
3268			   NULL,
3269			   wpas_dbus_p2p_peer_properties,
3270			   wpas_dbus_p2p_peer_signals);
3271
3272	if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path,
3273					       wpa_s->ifname, obj_desc))
3274		goto err;
3275
3276	return 0;
3277
3278err:
3279	free_dbus_object_desc(obj_desc);
3280	return -1;
3281}
3282
3283/**
3284 * wpas_dbus_unregister_peer - Unregister a peer object with dbus
3285 * @wpa_s: wpa_supplicant interface structure
3286 * @dev_addr: p2p device addr
3287 * Returns: 0 on success, -1 on failure
3288 *
3289 * Registers network representing object with dbus
3290 */
3291int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
3292				  const u8 *dev_addr)
3293{
3294	struct wpas_dbus_priv *ctrl_iface;
3295	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3296	int ret;
3297
3298	/* Do nothing if the control interface is not turned on */
3299	if (wpa_s == NULL || wpa_s->global == NULL ||
3300	    wpa_s->dbus_new_path == NULL)
3301		return 0;
3302	ctrl_iface = wpa_s->global->dbus;
3303	if (ctrl_iface == NULL)
3304		return 0;
3305
3306	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3307		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
3308		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
3309
3310	wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'",
3311		   peer_obj_path);
3312	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path);
3313
3314	return ret;
3315}
3316
3317
3318static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
3319	{ "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
3320	  wpas_dbus_getter_p2p_group_members,
3321	  NULL
3322	},
3323	{ "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o",
3324	  wpas_dbus_getter_p2p_group,
3325	  NULL
3326	},
3327	{ "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
3328	  wpas_dbus_getter_p2p_role,
3329	  NULL
3330	},
3331	{ "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
3332	  wpas_dbus_getter_p2p_group_ssid,
3333	  NULL
3334	},
3335	{ "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
3336	  wpas_dbus_getter_p2p_group_bssid,
3337	  NULL
3338	},
3339	{ "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q",
3340	  wpas_dbus_getter_p2p_group_frequency,
3341	  NULL
3342	},
3343	{ "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
3344	  wpas_dbus_getter_p2p_group_passphrase,
3345	  NULL
3346	},
3347	{ "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
3348	  wpas_dbus_getter_p2p_group_psk,
3349	  NULL
3350	},
3351	{ "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay",
3352	  wpas_dbus_getter_p2p_group_vendor_ext,
3353	  wpas_dbus_setter_p2p_group_vendor_ext
3354	},
3355	{ NULL, NULL, NULL, NULL, NULL }
3356};
3357
3358static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
3359	{ "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
3360	  {
3361		  { "peer", "o", ARG_OUT },
3362		  END_ARGS
3363	  }
3364	},
3365	{ "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
3366	  {
3367		  { "peer", "o", ARG_OUT },
3368		  END_ARGS
3369	  }
3370	},
3371	{ NULL, NULL, { END_ARGS } }
3372};
3373
3374/**
3375 * wpas_dbus_register_p2p_group - Register a p2p group object with dbus
3376 * @wpa_s: wpa_supplicant interface structure
3377 * @ssid: SSID struct
3378 * Returns: 0 on success, -1 on failure
3379 *
3380 * Registers p2p group representing object with dbus
3381 */
3382void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
3383				  struct wpa_ssid *ssid)
3384{
3385	struct wpas_dbus_priv *ctrl_iface;
3386	struct wpa_dbus_object_desc *obj_desc;
3387	char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3388
3389	/* Do nothing if the control interface is not turned on */
3390	if (wpa_s == NULL || wpa_s->global == NULL)
3391		return;
3392
3393	ctrl_iface = wpa_s->global->dbus;
3394	if (ctrl_iface == NULL)
3395		return;
3396
3397	if (wpa_s->dbus_groupobj_path) {
3398		wpa_printf(MSG_INFO, "%s: Group object '%s' already exists",
3399			   __func__, wpa_s->dbus_groupobj_path);
3400		return;
3401	}
3402
3403	if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
3404		return;
3405
3406	wpa_s->dbus_groupobj_path = os_strdup(group_obj_path);
3407	if (wpa_s->dbus_groupobj_path == NULL)
3408		return;
3409
3410	wpa_printf(MSG_INFO, "dbus: Register group object '%s'",
3411		   group_obj_path);
3412	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3413	if (!obj_desc) {
3414		wpa_printf(MSG_ERROR, "Not enough memory "
3415			   "to create object description");
3416		goto err;
3417	}
3418
3419	wpas_dbus_register(obj_desc, wpa_s, NULL, NULL,
3420			   wpas_dbus_p2p_group_properties,
3421			   wpas_dbus_p2p_group_signals);
3422
3423	if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path,
3424					       wpa_s->ifname, obj_desc))
3425		goto err;
3426
3427	return;
3428
3429err:
3430	if (wpa_s->dbus_groupobj_path) {
3431		os_free(wpa_s->dbus_groupobj_path);
3432		wpa_s->dbus_groupobj_path = NULL;
3433	}
3434
3435	free_dbus_object_desc(obj_desc);
3436}
3437
3438/**
3439 * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus
3440 * @wpa_s: wpa_supplicant interface structure
3441 * @ssid: network name of the p2p group started
3442 */
3443void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
3444				    const struct wpa_ssid *ssid)
3445{
3446	struct wpas_dbus_priv *ctrl_iface;
3447
3448	/* Do nothing if the control interface is not turned on */
3449	if (wpa_s == NULL || wpa_s->global == NULL)
3450		return;
3451
3452	ctrl_iface = wpa_s->global->dbus;
3453	if (ctrl_iface == NULL)
3454		return;
3455
3456	if (!wpa_s->dbus_groupobj_path) {
3457		wpa_printf(MSG_DEBUG,
3458			   "%s: Group object '%s' already unregistered",
3459			   __func__, wpa_s->dbus_groupobj_path);
3460		return;
3461	}
3462
3463	wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'",
3464		   wpa_s->dbus_groupobj_path);
3465
3466	wpa_dbus_unregister_object_per_iface(ctrl_iface,
3467					     wpa_s->dbus_groupobj_path);
3468
3469	os_free(wpa_s->dbus_groupobj_path);
3470	wpa_s->dbus_groupobj_path = NULL;
3471}
3472
3473static const struct wpa_dbus_property_desc
3474wpas_dbus_p2p_groupmember_properties[] = {
3475	{ NULL, NULL, NULL, NULL, NULL }
3476};
3477
3478/**
3479 * wpas_dbus_register_p2p_groupmember - Register a p2p groupmember
3480 * object with dbus
3481 * @wpa_s: wpa_supplicant interface structure
3482 * @p2p_if_addr: i/f addr of the device joining this group
3483 *
3484 * Registers p2p groupmember representing object with dbus
3485 */
3486void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
3487					const u8 *p2p_if_addr)
3488{
3489	struct wpas_dbus_priv *ctrl_iface;
3490	struct wpa_dbus_object_desc *obj_desc = NULL;
3491	struct groupmember_handler_args *arg;
3492	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3493
3494	/* Do nothing if the control interface is not turned on */
3495	if (wpa_s == NULL || wpa_s->global == NULL)
3496		return;
3497
3498	ctrl_iface = wpa_s->global->dbus;
3499	if (ctrl_iface == NULL)
3500		return;
3501
3502	if (!wpa_s->dbus_groupobj_path)
3503		return;
3504
3505	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3506		"%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
3507		wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
3508
3509	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3510	if (!obj_desc) {
3511		wpa_printf(MSG_ERROR, "Not enough memory "
3512			   "to create object description");
3513		goto err;
3514	}
3515
3516	/* allocate memory for handlers arguments */
3517	arg = os_zalloc(sizeof(struct groupmember_handler_args));
3518	if (!arg) {
3519		wpa_printf(MSG_ERROR, "Not enough memory "
3520			   "to create arguments for method");
3521		goto err;
3522	}
3523
3524	arg->wpa_s = wpa_s;
3525	os_memcpy(arg->member_addr, p2p_if_addr, ETH_ALEN);
3526
3527	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
3528			   wpas_dbus_p2p_groupmember_properties, NULL);
3529
3530	if (wpa_dbus_register_object_per_iface(ctrl_iface, groupmember_obj_path,
3531					       wpa_s->ifname, obj_desc))
3532		goto err;
3533
3534	wpa_printf(MSG_INFO,
3535		   "dbus: Registered group member object '%s' successfully",
3536		   groupmember_obj_path);
3537	return;
3538
3539err:
3540	free_dbus_object_desc(obj_desc);
3541}
3542
3543/**
3544 * wpas_dbus_unregister_p2p_groupmember - Unregister a p2p groupmember
3545 * object with dbus
3546 * @wpa_s: wpa_supplicant interface structure
3547 * @p2p_if_addr: i/f addr of the device joining this group
3548 *
3549 * Unregisters p2p groupmember representing object with dbus
3550 */
3551void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
3552					  const u8 *p2p_if_addr)
3553{
3554	struct wpas_dbus_priv *ctrl_iface;
3555	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3556
3557	/* Do nothing if the control interface is not turned on */
3558	if (wpa_s == NULL || wpa_s->global == NULL)
3559		return;
3560
3561	ctrl_iface = wpa_s->global->dbus;
3562	if (ctrl_iface == NULL)
3563		return;
3564
3565	if (!wpa_s->dbus_groupobj_path)
3566		return;
3567
3568	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3569		"%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
3570		wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
3571
3572	wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path);
3573}
3574
3575
3576static const struct wpa_dbus_property_desc
3577	wpas_dbus_persistent_group_properties[] = {
3578	{ "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
3579	  wpas_dbus_getter_persistent_group_properties,
3580	  wpas_dbus_setter_persistent_group_properties
3581	},
3582	{ NULL, NULL, NULL, NULL, NULL }
3583};
3584
3585/* No signals intended for persistent group objects */
3586
3587/**
3588 * wpas_dbus_register_persistent_group - Register a configured(saved)
3589 *	persistent group with dbus
3590 * @wpa_s: wpa_supplicant interface structure
3591 * @ssid: persistent group (still represented as a network within wpa)
3592 *	  configuration data
3593 * Returns: 0 on success, -1 on failure
3594 *
3595 * Registers a persistent group representing object with dbus.
3596 */
3597int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
3598					struct wpa_ssid *ssid)
3599{
3600	struct wpas_dbus_priv *ctrl_iface;
3601	struct wpa_dbus_object_desc *obj_desc;
3602	struct network_handler_args *arg;
3603	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3604
3605	/* Do nothing if the control interface is not turned on */
3606	if (wpa_s == NULL || wpa_s->global == NULL)
3607		return 0;
3608
3609	/* Make sure ssid is a persistent group */
3610	if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
3611		return -1; /* should we return w/o complaining? */
3612
3613	ctrl_iface = wpa_s->global->dbus;
3614	if (ctrl_iface == NULL)
3615		return 0;
3616
3617	/*
3618	 * Intentionally not coming up with different numbering scheme
3619	 * for persistent groups.
3620	 */
3621	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3622		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
3623		    wpa_s->dbus_new_path, ssid->id);
3624
3625	wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'",
3626		   pgrp_obj_path);
3627	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
3628	if (!obj_desc) {
3629		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
3630			   "object description");
3631		goto err;
3632	}
3633
3634	/*
3635	 * Reusing the same context structure as that for networks
3636	 * since these are represented using same data structure.
3637	 */
3638	/* allocate memory for handlers arguments */
3639	arg = os_zalloc(sizeof(struct network_handler_args));
3640	if (!arg) {
3641		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
3642			   "arguments for method");
3643		goto err;
3644	}
3645
3646	arg->wpa_s = wpa_s;
3647	arg->ssid = ssid;
3648
3649	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
3650			   wpas_dbus_persistent_group_properties,
3651			   NULL);
3652
3653	if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path,
3654					       wpa_s->ifname, obj_desc))
3655		goto err;
3656
3657	wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id);
3658
3659	return 0;
3660
3661err:
3662	free_dbus_object_desc(obj_desc);
3663	return -1;
3664}
3665
3666
3667/**
3668 * wpas_dbus_unregister_persistent_group - Unregister a persistent_group
3669 *	from dbus
3670 * @wpa_s: wpa_supplicant interface structure
3671 * @nid: network id
3672 * Returns: 0 on success, -1 on failure
3673 *
3674 * Unregisters persistent group representing object from dbus
3675 *
3676 * NOTE: There is a slight issue with the semantics here. While the
3677 * implementation simply means the persistent group is unloaded from memory,
3678 * it should not get interpreted as the group is actually being erased/removed
3679 * from persistent storage as well.
3680 */
3681int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
3682					  int nid)
3683{
3684	struct wpas_dbus_priv *ctrl_iface;
3685	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
3686	int ret;
3687
3688	/* Do nothing if the control interface is not turned on */
3689	if (wpa_s == NULL || wpa_s->global == NULL ||
3690	    wpa_s->dbus_new_path == NULL)
3691		return 0;
3692	ctrl_iface = wpa_s->global->dbus;
3693	if (ctrl_iface == NULL)
3694		return 0;
3695
3696	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3697		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
3698		    wpa_s->dbus_new_path, nid);
3699
3700	wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'",
3701		   pgrp_obj_path);
3702	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path);
3703
3704	if (!ret)
3705		wpas_dbus_signal_persistent_group_removed(wpa_s, nid);
3706
3707	return ret;
3708}
3709
3710#endif /* CONFIG_P2P */
3711