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