dbus_new_handlers.c revision 43cb578dfe2c492257636f6234a24178ed27789e
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 "eap_peer/eap_methods.h"
16#include "eapol_supp/eapol_supp_sm.h"
17#include "rsn_supp/wpa.h"
18#include "../config.h"
19#include "../wpa_supplicant_i.h"
20#include "../driver_i.h"
21#include "../notify.h"
22#include "../bss.h"
23#include "../scan.h"
24#include "../autoscan.h"
25#include "dbus_new_helpers.h"
26#include "dbus_new.h"
27#include "dbus_new_handlers.h"
28#include "dbus_dict_helpers.h"
29#include "dbus_common_i.h"
30
31static const char *debug_strings[] = {
32	"excessive", "msgdump", "debug", "info", "warning", "error", NULL
33};
34
35
36/**
37 * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
38 * @message: Pointer to incoming dbus message this error refers to
39 * @arg: Optional string appended to error message
40 * Returns: a dbus error message
41 *
42 * Convenience function to create and return an UnknownError
43 */
44DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
45					    const char *arg)
46{
47	/*
48	 * This function can be called as a result of a failure
49	 * within internal getter calls, which will call this function
50	 * with a NULL message parameter.  However, dbus_message_new_error
51	 * looks very unkindly (i.e, abort()) on a NULL message, so
52	 * in this case, we should not call it.
53	 */
54	if (message == NULL) {
55		wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error "
56			   "called with NULL message (arg=%s)",
57			   arg ? arg : "N/A");
58		return NULL;
59	}
60
61	return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
62				      arg);
63}
64
65
66/**
67 * wpas_dbus_error_iface_unknown - Return a new invalid interface error message
68 * @message: Pointer to incoming dbus message this error refers to
69 * Returns: A dbus error message
70 *
71 * Convenience function to create and return an invalid interface error
72 */
73static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
74{
75	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
76				      "wpa_supplicant knows nothing about "
77				      "this interface.");
78}
79
80
81/**
82 * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
83 * @message: Pointer to incoming dbus message this error refers to
84 * Returns: a dbus error message
85 *
86 * Convenience function to create and return an invalid network error
87 */
88static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
89{
90	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
91				      "There is no such a network in this "
92				      "interface.");
93}
94
95
96/**
97 * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
98 * @message: Pointer to incoming dbus message this error refers to
99 * Returns: a dbus error message
100 *
101 * Convenience function to create and return an invalid options error
102 */
103DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
104					  const char *arg)
105{
106	DBusMessage *reply;
107
108	reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
109				       "Did not receive correct message "
110				       "arguments.");
111	if (arg != NULL)
112		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
113					 DBUS_TYPE_INVALID);
114
115	return reply;
116}
117
118
119/**
120 * wpas_dbus_error_scan_error - Return a new ScanError error message
121 * @message: Pointer to incoming dbus message this error refers to
122 * @error: Optional string to be used as the error message
123 * Returns: a dbus error message
124 *
125 * Convenience function to create and return a scan error
126 */
127DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
128					 const char *error)
129{
130	DBusMessage *reply;
131
132	reply = dbus_message_new_error(message,
133				       WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
134				       error);
135
136	return reply;
137}
138
139
140static const char *dont_quote[] = {
141	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
142	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
143	"bssid", "scan_freq", "freq_list", NULL
144};
145
146static dbus_bool_t should_quote_opt(const char *key)
147{
148	int i = 0;
149	while (dont_quote[i] != NULL) {
150		if (os_strcmp(key, dont_quote[i]) == 0)
151			return FALSE;
152		i++;
153	}
154	return TRUE;
155}
156
157/**
158 * get_iface_by_dbus_path - Get a new network interface
159 * @global: Pointer to global data from wpa_supplicant_init()
160 * @path: Pointer to a dbus object path representing an interface
161 * Returns: Pointer to the interface or %NULL if not found
162 */
163static struct wpa_supplicant * get_iface_by_dbus_path(
164	struct wpa_global *global, const char *path)
165{
166	struct wpa_supplicant *wpa_s;
167
168	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
169		if (os_strcmp(wpa_s->dbus_new_path, path) == 0)
170			return wpa_s;
171	}
172	return NULL;
173}
174
175
176/**
177 * set_network_properties - Set properties of a configured network
178 * @wpa_s: wpa_supplicant structure for a network interface
179 * @ssid: wpa_ssid structure for a configured network
180 * @iter: DBus message iterator containing dictionary of network
181 * properties to set.
182 * @error: On failure, an error describing the failure
183 * Returns: TRUE if the request succeeds, FALSE if it failed
184 *
185 * Sets network configuration with parameters given id DBus dictionary
186 */
187dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
188				   struct wpa_ssid *ssid,
189				   DBusMessageIter *iter,
190				   DBusError *error)
191{
192	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
193	DBusMessageIter	iter_dict;
194	char *value = NULL;
195
196	if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
197		return FALSE;
198
199	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
200		size_t size = 50;
201		int ret;
202
203		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
204			goto error;
205
206		value = NULL;
207		if (entry.type == DBUS_TYPE_ARRAY &&
208		    entry.array_type == DBUS_TYPE_BYTE) {
209			if (entry.array_len <= 0)
210				goto error;
211
212			size = entry.array_len * 2 + 1;
213			value = os_zalloc(size);
214			if (value == NULL)
215				goto error;
216
217			ret = wpa_snprintf_hex(value, size,
218					       (u8 *) entry.bytearray_value,
219					       entry.array_len);
220			if (ret <= 0)
221				goto error;
222		} else if (entry.type == DBUS_TYPE_STRING) {
223			if (should_quote_opt(entry.key)) {
224				size = os_strlen(entry.str_value);
225				if (size <= 0)
226					goto error;
227
228				size += 3;
229				value = os_zalloc(size);
230				if (value == NULL)
231					goto error;
232
233				ret = os_snprintf(value, size, "\"%s\"",
234						  entry.str_value);
235				if (ret < 0 || (size_t) ret != (size - 1))
236					goto error;
237			} else {
238				value = os_strdup(entry.str_value);
239				if (value == NULL)
240					goto error;
241			}
242		} else if (entry.type == DBUS_TYPE_UINT32) {
243			value = os_zalloc(size);
244			if (value == NULL)
245				goto error;
246
247			ret = os_snprintf(value, size, "%u",
248					  entry.uint32_value);
249			if (ret <= 0)
250				goto error;
251		} else if (entry.type == DBUS_TYPE_INT32) {
252			value = os_zalloc(size);
253			if (value == NULL)
254				goto error;
255
256			ret = os_snprintf(value, size, "%d",
257					  entry.int32_value);
258			if (ret <= 0)
259				goto error;
260		} else
261			goto error;
262
263		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
264			goto error;
265
266		if ((os_strcmp(entry.key, "psk") == 0 &&
267		     value[0] == '"' && ssid->ssid_len) ||
268		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
269			wpa_config_update_psk(ssid);
270		else if (os_strcmp(entry.key, "priority") == 0)
271			wpa_config_update_prio_list(wpa_s->conf);
272
273		os_free(value);
274		value = NULL;
275		wpa_dbus_dict_entry_clear(&entry);
276	}
277
278	return TRUE;
279
280error:
281	os_free(value);
282	wpa_dbus_dict_entry_clear(&entry);
283	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
284			     "invalid message format");
285	return FALSE;
286}
287
288
289/**
290 * wpas_dbus_simple_property_getter - Get basic type property
291 * @iter: Message iter to use when appending arguments
292 * @type: DBus type of property (must be basic type)
293 * @val: pointer to place holding property value
294 * @error: On failure an error describing the failure
295 * Returns: TRUE if the request was successful, FALSE if it failed
296 *
297 * Generic getter for basic type properties. Type is required to be basic.
298 */
299dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
300					     const int type,
301					     const void *val,
302					     DBusError *error)
303{
304	DBusMessageIter variant_iter;
305
306	if (!dbus_type_is_basic(type)) {
307		dbus_set_error(error, DBUS_ERROR_FAILED,
308		               "%s: given type is not basic", __func__);
309		return FALSE;
310	}
311
312	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
313	                                      wpa_dbus_type_as_string(type),
314	                                      &variant_iter))
315		goto error;
316
317	if (!dbus_message_iter_append_basic(&variant_iter, type, val))
318		goto error;
319
320	if (!dbus_message_iter_close_container(iter, &variant_iter))
321		goto error;
322
323	return TRUE;
324
325error:
326	dbus_set_error(error, DBUS_ERROR_FAILED,
327	               "%s: error constructing reply", __func__);
328	return FALSE;
329}
330
331
332/**
333 * wpas_dbus_simple_property_setter - Set basic type property
334 * @message: Pointer to incoming dbus message
335 * @type: DBus type of property (must be basic type)
336 * @val: pointer to place where value being set will be stored
337 * Returns: TRUE if the request was successful, FALSE if it failed
338 *
339 * Generic setter for basic type properties. Type is required to be basic.
340 */
341dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
342					     DBusError *error,
343					     const int type, void *val)
344{
345	DBusMessageIter variant_iter;
346
347	if (!dbus_type_is_basic(type)) {
348		dbus_set_error(error, DBUS_ERROR_FAILED,
349			       "%s: given type is not basic", __func__);
350		return FALSE;
351	}
352
353	/* Look at the new value */
354	dbus_message_iter_recurse(iter, &variant_iter);
355	if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
356		dbus_set_error_const(error, DBUS_ERROR_FAILED,
357				     "wrong property type");
358		return FALSE;
359	}
360	dbus_message_iter_get_basic(&variant_iter, val);
361
362	return TRUE;
363}
364
365
366/**
367 * wpas_dbus_simple_array_property_getter - Get array type property
368 * @iter: Pointer to incoming dbus message iterator
369 * @type: DBus type of property array elements (must be basic type)
370 * @array: pointer to array of elements to put into response message
371 * @array_len: length of above array
372 * @error: a pointer to an error to fill on failure
373 * Returns: TRUE if the request succeeded, FALSE if it failed
374 *
375 * Generic getter for array type properties. Array elements type is
376 * required to be basic.
377 */
378dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
379						   const int type,
380						   const void *array,
381						   size_t array_len,
382						   DBusError *error)
383{
384	DBusMessageIter variant_iter, array_iter;
385	char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
386	const char *sub_type_str;
387	size_t element_size, i;
388
389	if (!dbus_type_is_basic(type)) {
390		dbus_set_error(error, DBUS_ERROR_FAILED,
391		               "%s: given type is not basic", __func__);
392		return FALSE;
393	}
394
395	sub_type_str = wpa_dbus_type_as_string(type);
396	type_str[1] = sub_type_str[0];
397
398	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
399					      type_str, &variant_iter)) {
400		dbus_set_error(error, DBUS_ERROR_FAILED,
401		               "%s: failed to construct message 1", __func__);
402		return FALSE;
403	}
404
405	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
406					      sub_type_str, &array_iter)) {
407		dbus_set_error(error, DBUS_ERROR_FAILED,
408		               "%s: failed to construct message 2", __func__);
409		return FALSE;
410	}
411
412	switch(type) {
413	case DBUS_TYPE_BYTE:
414	case DBUS_TYPE_BOOLEAN:
415		element_size = 1;
416		break;
417	case DBUS_TYPE_INT16:
418	case DBUS_TYPE_UINT16:
419		element_size = sizeof(uint16_t);
420		break;
421	case DBUS_TYPE_INT32:
422	case DBUS_TYPE_UINT32:
423		element_size = sizeof(uint32_t);
424		break;
425	case DBUS_TYPE_INT64:
426	case DBUS_TYPE_UINT64:
427		element_size = sizeof(uint64_t);
428		break;
429	case DBUS_TYPE_DOUBLE:
430		element_size = sizeof(double);
431		break;
432	case DBUS_TYPE_STRING:
433	case DBUS_TYPE_OBJECT_PATH:
434		element_size = sizeof(char *);
435		break;
436	default:
437		dbus_set_error(error, DBUS_ERROR_FAILED,
438		               "%s: unknown element type %d", __func__, type);
439		return FALSE;
440	}
441
442	for (i = 0; i < array_len; i++) {
443		if (!dbus_message_iter_append_basic(&array_iter, type,
444						    array + i * element_size)) {
445			dbus_set_error(error, DBUS_ERROR_FAILED,
446				       "%s: failed to construct message 2.5",
447				       __func__);
448			return FALSE;
449		}
450	}
451
452	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
453		dbus_set_error(error, DBUS_ERROR_FAILED,
454		               "%s: failed to construct message 3", __func__);
455		return FALSE;
456	}
457
458	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
459		dbus_set_error(error, DBUS_ERROR_FAILED,
460		               "%s: failed to construct message 4", __func__);
461		return FALSE;
462	}
463
464	return TRUE;
465}
466
467
468/**
469 * wpas_dbus_simple_array_array_property_getter - Get array array type property
470 * @iter: Pointer to incoming dbus message iterator
471 * @type: DBus type of property array elements (must be basic type)
472 * @array: pointer to array of elements to put into response message
473 * @array_len: length of above array
474 * @error: a pointer to an error to fill on failure
475 * Returns: TRUE if the request succeeded, FALSE if it failed
476 *
477 * Generic getter for array type properties. Array elements type is
478 * required to be basic.
479 */
480dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
481							 const int type,
482							 struct wpabuf **array,
483							 size_t array_len,
484							 DBusError *error)
485{
486	DBusMessageIter variant_iter, array_iter;
487	char type_str[] = "aa?";
488	char inner_type_str[] = "a?";
489	const char *sub_type_str;
490	size_t i;
491
492	if (!dbus_type_is_basic(type)) {
493		dbus_set_error(error, DBUS_ERROR_FAILED,
494			       "%s: given type is not basic", __func__);
495		return FALSE;
496	}
497
498	sub_type_str = wpa_dbus_type_as_string(type);
499	type_str[2] = sub_type_str[0];
500	inner_type_str[1] = sub_type_str[0];
501
502	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
503					      type_str, &variant_iter)) {
504		dbus_set_error(error, DBUS_ERROR_FAILED,
505			       "%s: failed to construct message 1", __func__);
506		return FALSE;
507	}
508	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
509					      inner_type_str, &array_iter)) {
510		dbus_set_error(error, DBUS_ERROR_FAILED,
511			       "%s: failed to construct message 2", __func__);
512		return FALSE;
513	}
514
515	for (i = 0; i < array_len; i++) {
516		wpa_dbus_dict_bin_array_add_element(&array_iter,
517						    wpabuf_head(array[i]),
518						    wpabuf_len(array[i]));
519
520	}
521
522	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
523		dbus_set_error(error, DBUS_ERROR_FAILED,
524			       "%s: failed to close message 2", __func__);
525		return FALSE;
526	}
527
528	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
529		dbus_set_error(error, DBUS_ERROR_FAILED,
530			       "%s: failed to close message 1", __func__);
531		return FALSE;
532	}
533
534	return TRUE;
535}
536
537
538/**
539 * wpas_dbus_handler_create_interface - Request registration of a network iface
540 * @message: Pointer to incoming dbus message
541 * @global: %wpa_supplicant global data structure
542 * Returns: The object path of the new interface object,
543 *          or a dbus error message with more information
544 *
545 * Handler function for "CreateInterface" method call. Handles requests
546 * by dbus clients to register a network interface that wpa_supplicant
547 * will manage.
548 */
549DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
550						 struct wpa_global *global)
551{
552	DBusMessageIter iter_dict;
553	DBusMessage *reply = NULL;
554	DBusMessageIter iter;
555	struct wpa_dbus_dict_entry entry;
556	char *driver = NULL;
557	char *ifname = NULL;
558	char *confname = NULL;
559	char *bridge_ifname = NULL;
560
561	dbus_message_iter_init(message, &iter);
562
563	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
564		goto error;
565	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
566		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
567			goto error;
568		if (!os_strcmp(entry.key, "Driver") &&
569		    (entry.type == DBUS_TYPE_STRING)) {
570			os_free(driver);
571			driver = os_strdup(entry.str_value);
572			wpa_dbus_dict_entry_clear(&entry);
573			if (driver == NULL)
574				goto error;
575		} else if (!os_strcmp(entry.key, "Ifname") &&
576			   (entry.type == DBUS_TYPE_STRING)) {
577			os_free(ifname);
578			ifname = os_strdup(entry.str_value);
579			wpa_dbus_dict_entry_clear(&entry);
580			if (ifname == NULL)
581				goto error;
582		} else if (!os_strcmp(entry.key, "ConfigFile") &&
583			   (entry.type == DBUS_TYPE_STRING)) {
584			os_free(confname);
585			confname = os_strdup(entry.str_value);
586			wpa_dbus_dict_entry_clear(&entry);
587			if (confname == NULL)
588				goto error;
589		} else if (!os_strcmp(entry.key, "BridgeIfname") &&
590			   (entry.type == DBUS_TYPE_STRING)) {
591			os_free(bridge_ifname);
592			bridge_ifname = os_strdup(entry.str_value);
593			wpa_dbus_dict_entry_clear(&entry);
594			if (bridge_ifname == NULL)
595				goto error;
596		} else {
597			wpa_dbus_dict_entry_clear(&entry);
598			goto error;
599		}
600	}
601
602	if (ifname == NULL)
603		goto error; /* Required Ifname argument missing */
604
605	/*
606	 * Try to get the wpa_supplicant record for this iface, return
607	 * an error if we already control it.
608	 */
609	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
610		reply = dbus_message_new_error(message,
611					       WPAS_DBUS_ERROR_IFACE_EXISTS,
612					       "wpa_supplicant already "
613					       "controls this interface.");
614	} else {
615		struct wpa_supplicant *wpa_s;
616		struct wpa_interface iface;
617		os_memset(&iface, 0, sizeof(iface));
618		iface.driver = driver;
619		iface.ifname = ifname;
620		iface.confname = confname;
621		iface.bridge_ifname = bridge_ifname;
622		/* Otherwise, have wpa_supplicant attach to it. */
623		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
624			const char *path = wpa_s->dbus_new_path;
625			reply = dbus_message_new_method_return(message);
626			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
627			                         &path, DBUS_TYPE_INVALID);
628		} else {
629			reply = wpas_dbus_error_unknown_error(
630				message, "wpa_supplicant couldn't grab this "
631				"interface.");
632		}
633	}
634
635out:
636	os_free(driver);
637	os_free(ifname);
638	os_free(confname);
639	os_free(bridge_ifname);
640	return reply;
641
642error:
643	reply = wpas_dbus_error_invalid_args(message, NULL);
644	goto out;
645}
646
647
648/**
649 * wpas_dbus_handler_remove_interface - Request deregistration of an interface
650 * @message: Pointer to incoming dbus message
651 * @global: wpa_supplicant global data structure
652 * Returns: a dbus message containing a UINT32 indicating success (1) or
653 *          failure (0), or returns a dbus error message with more information
654 *
655 * Handler function for "removeInterface" method call.  Handles requests
656 * by dbus clients to deregister a network interface that wpa_supplicant
657 * currently manages.
658 */
659DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
660						 struct wpa_global *global)
661{
662	struct wpa_supplicant *wpa_s;
663	char *path;
664	DBusMessage *reply = NULL;
665
666	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
667			      DBUS_TYPE_INVALID);
668
669	wpa_s = get_iface_by_dbus_path(global, path);
670	if (wpa_s == NULL)
671		reply = wpas_dbus_error_iface_unknown(message);
672	else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
673		reply = wpas_dbus_error_unknown_error(
674			message, "wpa_supplicant couldn't remove this "
675			"interface.");
676	}
677
678	return reply;
679}
680
681
682/**
683 * wpas_dbus_handler_get_interface - Get the object path for an interface name
684 * @message: Pointer to incoming dbus message
685 * @global: %wpa_supplicant global data structure
686 * Returns: The object path of the interface object,
687 *          or a dbus error message with more information
688 *
689 * Handler function for "getInterface" method call.
690 */
691DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
692					      struct wpa_global *global)
693{
694	DBusMessage *reply = NULL;
695	const char *ifname;
696	const char *path;
697	struct wpa_supplicant *wpa_s;
698
699	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
700			      DBUS_TYPE_INVALID);
701
702	wpa_s = wpa_supplicant_get_iface(global, ifname);
703	if (wpa_s == NULL)
704		return wpas_dbus_error_iface_unknown(message);
705
706	path = wpa_s->dbus_new_path;
707	reply = dbus_message_new_method_return(message);
708	if (reply == NULL)
709		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
710					      NULL);
711	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
712				      DBUS_TYPE_INVALID)) {
713		dbus_message_unref(reply);
714		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
715					      NULL);
716	}
717
718	return reply;
719}
720
721
722/**
723 * wpas_dbus_getter_debug_level - Get debug level
724 * @iter: Pointer to incoming dbus message iter
725 * @error: Location to store error on failure
726 * @user_data: Function specific data
727 * Returns: TRUE on success, FALSE on failure
728 *
729 * Getter for "DebugLevel" property.
730 */
731dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
732					 DBusError *error,
733					 void *user_data)
734{
735	const char *str;
736	int idx = wpa_debug_level;
737
738	if (idx < 0)
739		idx = 0;
740	if (idx > 5)
741		idx = 5;
742	str = debug_strings[idx];
743	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
744						&str, error);
745}
746
747
748/**
749 * wpas_dbus_getter_debug_timestamp - Get debug timestamp
750 * @iter: Pointer to incoming dbus message iter
751 * @error: Location to store error on failure
752 * @user_data: Function specific data
753 * Returns: TRUE on success, FALSE on failure
754 *
755 * Getter for "DebugTimestamp" property.
756 */
757dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
758                                             DBusError *error,
759                                             void *user_data)
760{
761	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
762						&wpa_debug_timestamp, error);
763
764}
765
766
767/**
768 * wpas_dbus_getter_debug_show_keys - Get debug show keys
769 * @iter: Pointer to incoming dbus message iter
770 * @error: Location to store error on failure
771 * @user_data: Function specific data
772 * Returns: TRUE on success, FALSE on failure
773 *
774 * Getter for "DebugShowKeys" property.
775 */
776dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
777					     DBusError *error,
778					     void *user_data)
779{
780	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
781						&wpa_debug_show_keys, error);
782
783}
784
785/**
786 * wpas_dbus_setter_debug_level - Set debug level
787 * @iter: Pointer to incoming dbus message iter
788 * @error: Location to store error on failure
789 * @user_data: Function specific data
790 * Returns: TRUE on success, FALSE on failure
791 *
792 * Setter for "DebugLevel" property.
793 */
794dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
795					 DBusError *error, void *user_data)
796{
797	struct wpa_global *global = user_data;
798	const char *str = NULL;
799	int i, val = -1;
800
801	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
802					      &str))
803		return FALSE;
804
805	for (i = 0; debug_strings[i]; i++)
806		if (os_strcmp(debug_strings[i], str) == 0) {
807			val = i;
808			break;
809		}
810
811	if (val < 0 ||
812	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
813					    wpa_debug_show_keys)) {
814		dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
815				     "level value");
816		return FALSE;
817	}
818
819	return TRUE;
820}
821
822
823/**
824 * wpas_dbus_setter_debug_timestamp - Set debug timestamp
825 * @iter: Pointer to incoming dbus message iter
826 * @error: Location to store error on failure
827 * @user_data: Function specific data
828 * Returns: TRUE on success, FALSE on failure
829 *
830 * Setter for "DebugTimestamp" property.
831 */
832dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
833					     DBusError *error,
834					     void *user_data)
835{
836	struct wpa_global *global = user_data;
837	dbus_bool_t val;
838
839	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
840					      &val))
841		return FALSE;
842
843	wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
844					wpa_debug_show_keys);
845	return TRUE;
846}
847
848
849/**
850 * wpas_dbus_setter_debug_show_keys - Set debug show keys
851 * @iter: Pointer to incoming dbus message iter
852 * @error: Location to store error on failure
853 * @user_data: Function specific data
854 * Returns: TRUE on success, FALSE on failure
855 *
856 * Setter for "DebugShowKeys" property.
857 */
858dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
859					     DBusError *error,
860					     void *user_data)
861{
862	struct wpa_global *global = user_data;
863	dbus_bool_t val;
864
865	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
866					      &val))
867		return FALSE;
868
869	wpa_supplicant_set_debug_params(global, wpa_debug_level,
870					wpa_debug_timestamp,
871					val ? 1 : 0);
872	return TRUE;
873}
874
875
876/**
877 * wpas_dbus_getter_interfaces - Request registered interfaces list
878 * @iter: Pointer to incoming dbus message iter
879 * @error: Location to store error on failure
880 * @user_data: Function specific data
881 * Returns: TRUE on success, FALSE on failure
882 *
883 * Getter for "Interfaces" property. Handles requests
884 * by dbus clients to return list of registered interfaces objects
885 * paths
886 */
887dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
888					DBusError *error,
889					void *user_data)
890{
891	struct wpa_global *global = user_data;
892	struct wpa_supplicant *wpa_s;
893	const char **paths;
894	unsigned int i = 0, num = 0;
895	dbus_bool_t success;
896
897	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
898		num++;
899
900	paths = os_calloc(num, sizeof(char *));
901	if (!paths) {
902		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
903		return FALSE;
904	}
905
906	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
907		paths[i++] = wpa_s->dbus_new_path;
908
909	success = wpas_dbus_simple_array_property_getter(iter,
910							 DBUS_TYPE_OBJECT_PATH,
911							 paths, num, error);
912
913	os_free(paths);
914	return success;
915}
916
917
918/**
919 * wpas_dbus_getter_eap_methods - Request supported EAP methods list
920 * @iter: Pointer to incoming dbus message iter
921 * @error: Location to store error on failure
922 * @user_data: Function specific data
923 * Returns: TRUE on success, FALSE on failure
924 *
925 * Getter for "EapMethods" property. Handles requests
926 * by dbus clients to return list of strings with supported EAP methods
927 */
928dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
929					 DBusError *error, void *user_data)
930{
931	char **eap_methods;
932	size_t num_items = 0;
933	dbus_bool_t success;
934
935	eap_methods = eap_get_names_as_string_array(&num_items);
936	if (!eap_methods) {
937		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
938		return FALSE;
939	}
940
941	success = wpas_dbus_simple_array_property_getter(iter,
942							 DBUS_TYPE_STRING,
943							 eap_methods,
944							 num_items, error);
945
946	while (num_items)
947		os_free(eap_methods[--num_items]);
948	os_free(eap_methods);
949	return success;
950}
951
952
953/**
954 * wpas_dbus_getter_global_capabilities - Request supported global capabilities
955 * @iter: Pointer to incoming dbus message iter
956 * @error: Location to store error on failure
957 * @user_data: Function specific data
958 * Returns: TRUE on success, FALSE on failure
959 *
960 * Getter for "Capabilities" property. Handles requests by dbus clients to
961 * return a list of strings with supported capabilities like AP, RSN IBSS,
962 * and P2P that are determined at compile time.
963 */
964dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
965					         DBusError *error,
966					         void *user_data)
967{
968	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
969	size_t num_items = 0;
970
971#ifdef CONFIG_AP
972	capabilities[num_items++] = "ap";
973#endif /* CONFIG_AP */
974#ifdef CONFIG_IBSS_RSN
975	capabilities[num_items++] = "ibss-rsn";
976#endif /* CONFIG_IBSS_RSN */
977#ifdef CONFIG_P2P
978	capabilities[num_items++] = "p2p";
979#endif /* CONFIG_P2P */
980#ifdef CONFIG_INTERWORKING
981	capabilities[num_items++] = "interworking";
982#endif /* CONFIG_INTERWORKING */
983
984	return wpas_dbus_simple_array_property_getter(iter,
985						      DBUS_TYPE_STRING,
986						      capabilities,
987						      num_items, error);
988}
989
990
991static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
992				   char **type, DBusMessage **reply)
993{
994	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
995		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
996			   "Type must be a string");
997		*reply = wpas_dbus_error_invalid_args(
998			message, "Wrong Type value type. String required");
999		return -1;
1000	}
1001	dbus_message_iter_get_basic(var, type);
1002	return 0;
1003}
1004
1005
1006static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
1007				    struct wpa_driver_scan_params *params,
1008				    DBusMessage **reply)
1009{
1010	struct wpa_driver_scan_ssid *ssids = params->ssids;
1011	size_t ssids_num = 0;
1012	u8 *ssid;
1013	DBusMessageIter array_iter, sub_array_iter;
1014	char *val;
1015	int len;
1016
1017	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1018		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
1019			   "must be an array of arrays of bytes");
1020		*reply = wpas_dbus_error_invalid_args(
1021			message, "Wrong SSIDs value type. Array of arrays of "
1022			"bytes required");
1023		return -1;
1024	}
1025
1026	dbus_message_iter_recurse(var, &array_iter);
1027
1028	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1029	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
1030	{
1031		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
1032			   "must be an array of arrays of bytes");
1033		*reply = wpas_dbus_error_invalid_args(
1034			message, "Wrong SSIDs value type. Array of arrays of "
1035			"bytes required");
1036		return -1;
1037	}
1038
1039	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
1040	{
1041		if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
1042			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1043				   "Too many ssids specified on scan dbus "
1044				   "call");
1045			*reply = wpas_dbus_error_invalid_args(
1046				message, "Too many ssids specified. Specify "
1047				"at most four");
1048			return -1;
1049		}
1050
1051		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1052
1053		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1054
1055		if (len > MAX_SSID_LEN) {
1056			wpa_printf(MSG_DEBUG,
1057				   "wpas_dbus_handler_scan[dbus]: "
1058				   "SSID too long (len=%d max_len=%d)",
1059				   len, MAX_SSID_LEN);
1060			*reply = wpas_dbus_error_invalid_args(
1061				message, "Invalid SSID: too long");
1062			return -1;
1063		}
1064
1065		if (len != 0) {
1066			ssid = os_malloc(len);
1067			if (ssid == NULL) {
1068				wpa_printf(MSG_DEBUG,
1069					   "wpas_dbus_handler_scan[dbus]: "
1070					   "out of memory. Cannot allocate "
1071					   "memory for SSID");
1072				*reply = dbus_message_new_error(
1073					message, DBUS_ERROR_NO_MEMORY, NULL);
1074				return -1;
1075			}
1076			os_memcpy(ssid, val, len);
1077		} else {
1078			/* Allow zero-length SSIDs */
1079			ssid = NULL;
1080		}
1081
1082		ssids[ssids_num].ssid = ssid;
1083		ssids[ssids_num].ssid_len = len;
1084
1085		dbus_message_iter_next(&array_iter);
1086		ssids_num++;
1087	}
1088
1089	params->num_ssids = ssids_num;
1090	return 0;
1091}
1092
1093
1094static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
1095				  struct wpa_driver_scan_params *params,
1096				  DBusMessage **reply)
1097{
1098	u8 *ies = NULL, *nies;
1099	int ies_len = 0;
1100	DBusMessageIter array_iter, sub_array_iter;
1101	char *val;
1102	int len;
1103
1104	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1105		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
1106			   "be an array of arrays of bytes");
1107		*reply = wpas_dbus_error_invalid_args(
1108			message, "Wrong IEs value type. Array of arrays of "
1109			"bytes required");
1110		return -1;
1111	}
1112
1113	dbus_message_iter_recurse(var, &array_iter);
1114
1115	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1116	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
1117	{
1118		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
1119			   "be an array of arrays of bytes");
1120		*reply = wpas_dbus_error_invalid_args(
1121			message, "Wrong IEs value type. Array required");
1122		return -1;
1123	}
1124
1125	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
1126	{
1127		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1128
1129		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1130		if (len == 0) {
1131			dbus_message_iter_next(&array_iter);
1132			continue;
1133		}
1134
1135		nies = os_realloc(ies, ies_len + len);
1136		if (nies == NULL) {
1137			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1138				   "out of memory. Cannot allocate memory for "
1139				   "IE");
1140			os_free(ies);
1141			*reply = dbus_message_new_error(
1142				message, DBUS_ERROR_NO_MEMORY, NULL);
1143			return -1;
1144		}
1145		ies = nies;
1146		os_memcpy(ies + ies_len, val, len);
1147		ies_len += len;
1148
1149		dbus_message_iter_next(&array_iter);
1150	}
1151
1152	params->extra_ies = ies;
1153	params->extra_ies_len = ies_len;
1154	return 0;
1155}
1156
1157
1158static int wpas_dbus_get_scan_channels(DBusMessage *message,
1159				       DBusMessageIter *var,
1160				       struct wpa_driver_scan_params *params,
1161				       DBusMessage **reply)
1162{
1163	DBusMessageIter array_iter, sub_array_iter;
1164	int *freqs = NULL, *nfreqs;
1165	int freqs_num = 0;
1166
1167	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1168		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1169			   "Channels must be an array of structs");
1170		*reply = wpas_dbus_error_invalid_args(
1171			message, "Wrong Channels value type. Array of structs "
1172			"required");
1173		return -1;
1174	}
1175
1176	dbus_message_iter_recurse(var, &array_iter);
1177
1178	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
1179		wpa_printf(MSG_DEBUG,
1180			   "wpas_dbus_handler_scan[dbus]: Channels must be an "
1181			   "array of structs");
1182		*reply = wpas_dbus_error_invalid_args(
1183			message, "Wrong Channels value type. Array of structs "
1184			"required");
1185		return -1;
1186	}
1187
1188	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
1189	{
1190		int freq, width;
1191
1192		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1193
1194		if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
1195		    DBUS_TYPE_UINT32) {
1196			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1197				   "Channel must by specified by struct of "
1198				   "two UINT32s %c",
1199				   dbus_message_iter_get_arg_type(
1200					   &sub_array_iter));
1201			*reply = wpas_dbus_error_invalid_args(
1202				message, "Wrong Channel struct. Two UINT32s "
1203				"required");
1204			os_free(freqs);
1205			return -1;
1206		}
1207		dbus_message_iter_get_basic(&sub_array_iter, &freq);
1208
1209		if (!dbus_message_iter_next(&sub_array_iter) ||
1210		    dbus_message_iter_get_arg_type(&sub_array_iter) !=
1211		    DBUS_TYPE_UINT32) {
1212			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1213				   "Channel must by specified by struct of "
1214				   "two UINT32s");
1215			*reply = wpas_dbus_error_invalid_args(
1216				message,
1217				"Wrong Channel struct. Two UINT32s required");
1218			os_free(freqs);
1219			return -1;
1220		}
1221
1222		dbus_message_iter_get_basic(&sub_array_iter, &width);
1223
1224#define FREQS_ALLOC_CHUNK 32
1225		if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
1226			nfreqs = os_realloc_array(
1227				freqs, freqs_num + FREQS_ALLOC_CHUNK,
1228				sizeof(int));
1229			if (nfreqs == NULL)
1230				os_free(freqs);
1231			freqs = nfreqs;
1232		}
1233		if (freqs == NULL) {
1234			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1235				   "out of memory. can't allocate memory for "
1236				   "freqs");
1237			*reply = dbus_message_new_error(
1238				message, DBUS_ERROR_NO_MEMORY, NULL);
1239			return -1;
1240		}
1241
1242		freqs[freqs_num] = freq;
1243
1244		freqs_num++;
1245		dbus_message_iter_next(&array_iter);
1246	}
1247
1248	nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
1249	if (nfreqs == NULL)
1250		os_free(freqs);
1251	freqs = nfreqs;
1252	if (freqs == NULL) {
1253		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1254			   "out of memory. Can't allocate memory for freqs");
1255		*reply = dbus_message_new_error(
1256			message, DBUS_ERROR_NO_MEMORY, NULL);
1257		return -1;
1258	}
1259	freqs[freqs_num] = 0;
1260
1261	params->freqs = freqs;
1262	return 0;
1263}
1264
1265
1266static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
1267					 DBusMessageIter *var,
1268					 dbus_bool_t *allow,
1269					 DBusMessage **reply)
1270{
1271	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
1272		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1273			   "Type must be a boolean");
1274		*reply = wpas_dbus_error_invalid_args(
1275			message, "Wrong Type value type. Boolean required");
1276		return -1;
1277	}
1278	dbus_message_iter_get_basic(var, allow);
1279	return 0;
1280}
1281
1282
1283/**
1284 * wpas_dbus_handler_scan - Request a wireless scan on an interface
1285 * @message: Pointer to incoming dbus message
1286 * @wpa_s: wpa_supplicant structure for a network interface
1287 * Returns: NULL indicating success or DBus error message on failure
1288 *
1289 * Handler function for "Scan" method call of a network device. Requests
1290 * that wpa_supplicant perform a wireless scan as soon as possible
1291 * on a particular wireless interface.
1292 */
1293DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
1294				     struct wpa_supplicant *wpa_s)
1295{
1296	DBusMessage *reply = NULL;
1297	DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
1298	char *key = NULL, *type = NULL;
1299	struct wpa_driver_scan_params params;
1300	size_t i;
1301	dbus_bool_t allow_roam = 1;
1302
1303	os_memset(&params, 0, sizeof(params));
1304
1305	dbus_message_iter_init(message, &iter);
1306
1307	dbus_message_iter_recurse(&iter, &dict_iter);
1308
1309	while (dbus_message_iter_get_arg_type(&dict_iter) ==
1310			DBUS_TYPE_DICT_ENTRY) {
1311		dbus_message_iter_recurse(&dict_iter, &entry_iter);
1312		dbus_message_iter_get_basic(&entry_iter, &key);
1313		dbus_message_iter_next(&entry_iter);
1314		dbus_message_iter_recurse(&entry_iter, &variant_iter);
1315
1316		if (os_strcmp(key, "Type") == 0) {
1317			if (wpas_dbus_get_scan_type(message, &variant_iter,
1318						    &type, &reply) < 0)
1319				goto out;
1320		} else if (os_strcmp(key, "SSIDs") == 0) {
1321			if (wpas_dbus_get_scan_ssids(message, &variant_iter,
1322						     &params, &reply) < 0)
1323				goto out;
1324		} else if (os_strcmp(key, "IEs") == 0) {
1325			if (wpas_dbus_get_scan_ies(message, &variant_iter,
1326						   &params, &reply) < 0)
1327				goto out;
1328		} else if (os_strcmp(key, "Channels") == 0) {
1329			if (wpas_dbus_get_scan_channels(message, &variant_iter,
1330							&params, &reply) < 0)
1331				goto out;
1332		} else if (os_strcmp(key, "AllowRoam") == 0) {
1333			if (wpas_dbus_get_scan_allow_roam(message,
1334							  &variant_iter,
1335							  &allow_roam,
1336							  &reply) < 0)
1337				goto out;
1338		} else {
1339			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1340				   "Unknown argument %s", key);
1341			reply = wpas_dbus_error_invalid_args(message, key);
1342			goto out;
1343		}
1344
1345		dbus_message_iter_next(&dict_iter);
1346	}
1347
1348	if (!type) {
1349		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1350			   "Scan type not specified");
1351		reply = wpas_dbus_error_invalid_args(message, key);
1352		goto out;
1353	}
1354
1355	if (!os_strcmp(type, "passive")) {
1356		if (params.num_ssids || params.extra_ies_len) {
1357			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1358				   "SSIDs or IEs specified for passive scan.");
1359			reply = wpas_dbus_error_invalid_args(
1360				message, "You can specify only Channels in "
1361				"passive scan");
1362			goto out;
1363		} else if (params.freqs && params.freqs[0]) {
1364			if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1365				reply = wpas_dbus_error_scan_error(
1366					message, "Scan request rejected");
1367			}
1368		} else {
1369			wpa_s->scan_req = MANUAL_SCAN_REQ;
1370			wpa_supplicant_req_scan(wpa_s, 0, 0);
1371		}
1372	} else if (!os_strcmp(type, "active")) {
1373		if (!params.num_ssids) {
1374			/* Add wildcard ssid */
1375			params.num_ssids++;
1376		}
1377#ifdef CONFIG_AUTOSCAN
1378		autoscan_deinit(wpa_s);
1379#endif /* CONFIG_AUTOSCAN */
1380		if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1381			reply = wpas_dbus_error_scan_error(
1382				message, "Scan request rejected");
1383		}
1384	} else {
1385		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1386			   "Unknown scan type: %s", type);
1387		reply = wpas_dbus_error_invalid_args(message,
1388						     "Wrong scan type");
1389		goto out;
1390	}
1391
1392	if (!allow_roam)
1393		wpa_s->scan_res_handler = scan_only_handler;
1394
1395out:
1396	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
1397		os_free((u8 *) params.ssids[i].ssid);
1398	os_free((u8 *) params.extra_ies);
1399	os_free(params.freqs);
1400	return reply;
1401}
1402
1403
1404/*
1405 * wpas_dbus_handler_disconnect - Terminate the current connection
1406 * @message: Pointer to incoming dbus message
1407 * @wpa_s: wpa_supplicant structure for a network interface
1408 * Returns: NotConnected DBus error message if already not connected
1409 * or NULL otherwise.
1410 *
1411 * Handler function for "Disconnect" method call of network interface.
1412 */
1413DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
1414					   struct wpa_supplicant *wpa_s)
1415{
1416	if (wpa_s->current_ssid != NULL) {
1417		wpa_s->disconnected = 1;
1418		wpa_supplicant_deauthenticate(wpa_s,
1419					      WLAN_REASON_DEAUTH_LEAVING);
1420
1421		return NULL;
1422	}
1423
1424	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1425				      "This interface is not connected");
1426}
1427
1428
1429/**
1430 * wpas_dbus_new_iface_add_network - Add a new configured network
1431 * @message: Pointer to incoming dbus message
1432 * @wpa_s: wpa_supplicant structure for a network interface
1433 * Returns: A dbus message containing the object path of the new network
1434 *
1435 * Handler function for "AddNetwork" method call of a network interface.
1436 */
1437DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
1438					    struct wpa_supplicant *wpa_s)
1439{
1440	DBusMessage *reply = NULL;
1441	DBusMessageIter	iter;
1442	struct wpa_ssid *ssid = NULL;
1443	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1444	DBusError error;
1445
1446	dbus_message_iter_init(message, &iter);
1447
1448	ssid = wpa_config_add_network(wpa_s->conf);
1449	if (ssid == NULL) {
1450		wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
1451			   "can't add new interface.");
1452		reply = wpas_dbus_error_unknown_error(
1453			message,
1454			"wpa_supplicant could not add "
1455			"a network on this interface.");
1456		goto err;
1457	}
1458	wpas_notify_network_added(wpa_s, ssid);
1459	ssid->disabled = 1;
1460	wpa_config_set_network_defaults(ssid);
1461
1462	dbus_error_init(&error);
1463	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1464		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
1465			   "control interface couldn't set network "
1466			   "properties");
1467		reply = wpas_dbus_reply_new_from_error(message, &error,
1468						       DBUS_ERROR_INVALID_ARGS,
1469						       "Failed to add network");
1470		dbus_error_free(&error);
1471		goto err;
1472	}
1473
1474	/* Construct the object path for this network. */
1475	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1476		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
1477		    wpa_s->dbus_new_path, ssid->id);
1478
1479	reply = dbus_message_new_method_return(message);
1480	if (reply == NULL) {
1481		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1482					       NULL);
1483		goto err;
1484	}
1485	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1486				      DBUS_TYPE_INVALID)) {
1487		dbus_message_unref(reply);
1488		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1489					       NULL);
1490		goto err;
1491	}
1492
1493	return reply;
1494
1495err:
1496	if (ssid) {
1497		wpas_notify_network_removed(wpa_s, ssid);
1498		wpa_config_remove_network(wpa_s->conf, ssid->id);
1499	}
1500	return reply;
1501}
1502
1503
1504/**
1505 * wpas_dbus_handler_reassociate - Reassociate
1506 * @message: Pointer to incoming dbus message
1507 * @wpa_s: wpa_supplicant structure for a network interface
1508 * Returns: InterfaceDisabled DBus error message if disabled
1509 * or NULL otherwise.
1510 *
1511 * Handler function for "Reassociate" method call of network interface.
1512 */
1513DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
1514					    struct wpa_supplicant *wpa_s)
1515{
1516	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
1517		wpas_request_connection(wpa_s);
1518		return NULL;
1519	}
1520
1521	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
1522				      "This interface is disabled");
1523}
1524
1525
1526/**
1527 * wpas_dbus_handler_reattach - Reattach to current AP
1528 * @message: Pointer to incoming dbus message
1529 * @wpa_s: wpa_supplicant structure for a network interface
1530 * Returns: NotConnected DBus error message if not connected
1531 * or NULL otherwise.
1532 *
1533 * Handler function for "Reattach" method call of network interface.
1534 */
1535DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
1536					 struct wpa_supplicant *wpa_s)
1537{
1538	if (wpa_s->current_ssid != NULL) {
1539		wpa_s->reattach = 1;
1540		wpas_request_connection(wpa_s);
1541		return NULL;
1542	}
1543
1544	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1545				      "This interface is not connected");
1546}
1547
1548
1549/**
1550 * wpas_dbus_handler_remove_network - Remove a configured network
1551 * @message: Pointer to incoming dbus message
1552 * @wpa_s: wpa_supplicant structure for a network interface
1553 * Returns: NULL on success or dbus error on failure
1554 *
1555 * Handler function for "RemoveNetwork" method call of a network interface.
1556 */
1557DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
1558					       struct wpa_supplicant *wpa_s)
1559{
1560	DBusMessage *reply = NULL;
1561	const char *op;
1562	char *iface = NULL, *net_id = NULL;
1563	int id;
1564	struct wpa_ssid *ssid;
1565	int was_disabled;
1566
1567	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1568			      DBUS_TYPE_INVALID);
1569
1570	/* Extract the network ID and ensure the network */
1571	/* is actually a child of this interface */
1572	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
1573	if (iface == NULL || net_id == NULL ||
1574	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1575		reply = wpas_dbus_error_invalid_args(message, op);
1576		goto out;
1577	}
1578
1579	errno = 0;
1580	id = strtoul(net_id, NULL, 10);
1581	if (errno != 0) {
1582		reply = wpas_dbus_error_invalid_args(message, op);
1583		goto out;
1584	}
1585
1586	ssid = wpa_config_get_network(wpa_s->conf, id);
1587	if (ssid == NULL) {
1588		reply = wpas_dbus_error_network_unknown(message);
1589		goto out;
1590	}
1591
1592	was_disabled = ssid->disabled;
1593
1594	wpas_notify_network_removed(wpa_s, ssid);
1595
1596	if (ssid == wpa_s->current_ssid)
1597		wpa_supplicant_deauthenticate(wpa_s,
1598					      WLAN_REASON_DEAUTH_LEAVING);
1599	else if (!was_disabled && wpa_s->sched_scanning) {
1600		wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
1601			   "network from filters");
1602		wpa_supplicant_cancel_sched_scan(wpa_s);
1603		wpa_supplicant_req_scan(wpa_s, 0, 0);
1604	}
1605
1606	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1607		wpa_printf(MSG_ERROR,
1608			   "wpas_dbus_handler_remove_network[dbus]: "
1609			   "error occurred when removing network %d", id);
1610		reply = wpas_dbus_error_unknown_error(
1611			message, "error removing the specified network on "
1612			"this interface.");
1613		goto out;
1614	}
1615
1616out:
1617	os_free(iface);
1618	os_free(net_id);
1619	return reply;
1620}
1621
1622
1623static void remove_network(void *arg, struct wpa_ssid *ssid)
1624{
1625	struct wpa_supplicant *wpa_s = arg;
1626
1627	wpas_notify_network_removed(wpa_s, ssid);
1628
1629	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1630		wpa_printf(MSG_ERROR,
1631			   "wpas_dbus_handler_remove_all_networks[dbus]: "
1632			   "error occurred when removing network %d",
1633			   ssid->id);
1634		return;
1635	}
1636
1637	if (ssid == wpa_s->current_ssid)
1638		wpa_supplicant_deauthenticate(wpa_s,
1639					      WLAN_REASON_DEAUTH_LEAVING);
1640}
1641
1642
1643/**
1644 * wpas_dbus_handler_remove_all_networks - Remove all configured networks
1645 * @message: Pointer to incoming dbus message
1646 * @wpa_s: wpa_supplicant structure for a network interface
1647 * Returns: NULL on success or dbus error on failure
1648 *
1649 * Handler function for "RemoveAllNetworks" method call of a network interface.
1650 */
1651DBusMessage * wpas_dbus_handler_remove_all_networks(
1652	DBusMessage *message, struct wpa_supplicant *wpa_s)
1653{
1654	if (wpa_s->sched_scanning)
1655		wpa_supplicant_cancel_sched_scan(wpa_s);
1656
1657	/* NB: could check for failure and return an error */
1658	wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
1659	return NULL;
1660}
1661
1662
1663/**
1664 * wpas_dbus_handler_select_network - Attempt association with a network
1665 * @message: Pointer to incoming dbus message
1666 * @wpa_s: wpa_supplicant structure for a network interface
1667 * Returns: NULL on success or dbus error on failure
1668 *
1669 * Handler function for "SelectNetwork" method call of network interface.
1670 */
1671DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
1672					       struct wpa_supplicant *wpa_s)
1673{
1674	DBusMessage *reply = NULL;
1675	const char *op;
1676	char *iface = NULL, *net_id = NULL;
1677	int id;
1678	struct wpa_ssid *ssid;
1679
1680	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1681			      DBUS_TYPE_INVALID);
1682
1683	/* Extract the network ID and ensure the network */
1684	/* is actually a child of this interface */
1685	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
1686	if (iface == NULL || net_id == NULL ||
1687	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1688		reply = wpas_dbus_error_invalid_args(message, op);
1689		goto out;
1690	}
1691
1692	errno = 0;
1693	id = strtoul(net_id, NULL, 10);
1694	if (errno != 0) {
1695		reply = wpas_dbus_error_invalid_args(message, op);
1696		goto out;
1697	}
1698
1699	ssid = wpa_config_get_network(wpa_s->conf, id);
1700	if (ssid == NULL) {
1701		reply = wpas_dbus_error_network_unknown(message);
1702		goto out;
1703	}
1704
1705	/* Finally, associate with the network */
1706	wpa_supplicant_select_network(wpa_s, ssid);
1707
1708out:
1709	os_free(iface);
1710	os_free(net_id);
1711	return reply;
1712}
1713
1714
1715/**
1716 * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
1717 * @message: Pointer to incoming dbus message
1718 * @wpa_s: wpa_supplicant structure for a network interface
1719 * Returns: NULL on success or dbus error on failure
1720 *
1721 * Handler function for "NetworkReply" method call of network interface.
1722 */
1723DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
1724					      struct wpa_supplicant *wpa_s)
1725{
1726#ifdef IEEE8021X_EAPOL
1727	DBusMessage *reply = NULL;
1728	const char *op, *field, *value;
1729	char *iface = NULL, *net_id = NULL;
1730	int id;
1731	struct wpa_ssid *ssid;
1732
1733	if (!dbus_message_get_args(message, NULL,
1734	                           DBUS_TYPE_OBJECT_PATH, &op,
1735	                           DBUS_TYPE_STRING, &field,
1736	                           DBUS_TYPE_STRING, &value,
1737			           DBUS_TYPE_INVALID))
1738		return wpas_dbus_error_invalid_args(message, NULL);
1739
1740	/* Extract the network ID and ensure the network */
1741	/* is actually a child of this interface */
1742	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
1743	if (iface == NULL || net_id == NULL ||
1744	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1745		reply = wpas_dbus_error_invalid_args(message, op);
1746		goto out;
1747	}
1748
1749	errno = 0;
1750	id = strtoul(net_id, NULL, 10);
1751	if (errno != 0) {
1752		reply = wpas_dbus_error_invalid_args(message, net_id);
1753		goto out;
1754	}
1755
1756	ssid = wpa_config_get_network(wpa_s->conf, id);
1757	if (ssid == NULL) {
1758		reply = wpas_dbus_error_network_unknown(message);
1759		goto out;
1760	}
1761
1762	if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
1763						      field, value) < 0)
1764		reply = wpas_dbus_error_invalid_args(message, field);
1765	else {
1766		/* Tell EAP to retry immediately */
1767		eapol_sm_notify_ctrl_response(wpa_s->eapol);
1768	}
1769
1770out:
1771	os_free(iface);
1772	os_free(net_id);
1773	return reply;
1774#else /* IEEE8021X_EAPOL */
1775	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1776	return wpas_dbus_error_unknown_error(message, "802.1X not included");
1777#endif /* IEEE8021X_EAPOL */
1778}
1779
1780
1781#ifndef CONFIG_NO_CONFIG_BLOBS
1782
1783/**
1784 * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
1785 * @message: Pointer to incoming dbus message
1786 * @wpa_s: %wpa_supplicant data structure
1787 * Returns: A dbus message containing an error on failure or NULL on success
1788 *
1789 * Asks wpa_supplicant to internally store a binary blobs.
1790 */
1791DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
1792					 struct wpa_supplicant *wpa_s)
1793{
1794	DBusMessage *reply = NULL;
1795	DBusMessageIter	iter, array_iter;
1796
1797	char *blob_name;
1798	u8 *blob_data;
1799	int blob_len;
1800	struct wpa_config_blob *blob = NULL;
1801
1802	dbus_message_iter_init(message, &iter);
1803	dbus_message_iter_get_basic(&iter, &blob_name);
1804
1805	if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
1806		return dbus_message_new_error(message,
1807					      WPAS_DBUS_ERROR_BLOB_EXISTS,
1808					      NULL);
1809	}
1810
1811	dbus_message_iter_next(&iter);
1812	dbus_message_iter_recurse(&iter, &array_iter);
1813
1814	dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
1815
1816	blob = os_zalloc(sizeof(*blob));
1817	if (!blob) {
1818		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1819					       NULL);
1820		goto err;
1821	}
1822
1823	blob->data = os_malloc(blob_len);
1824	if (!blob->data) {
1825		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1826					       NULL);
1827		goto err;
1828	}
1829	os_memcpy(blob->data, blob_data, blob_len);
1830
1831	blob->len = blob_len;
1832	blob->name = os_strdup(blob_name);
1833	if (!blob->name) {
1834		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1835					       NULL);
1836		goto err;
1837	}
1838
1839	wpa_config_set_blob(wpa_s->conf, blob);
1840	wpas_notify_blob_added(wpa_s, blob->name);
1841
1842	return reply;
1843
1844err:
1845	if (blob) {
1846		os_free(blob->name);
1847		os_free(blob->data);
1848		os_free(blob);
1849	}
1850	return reply;
1851}
1852
1853
1854/**
1855 * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
1856 * @message: Pointer to incoming dbus message
1857 * @wpa_s: %wpa_supplicant data structure
1858 * Returns: A dbus message containing array of bytes (blob)
1859 *
1860 * Gets one wpa_supplicant's binary blobs.
1861 */
1862DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
1863					 struct wpa_supplicant *wpa_s)
1864{
1865	DBusMessage *reply = NULL;
1866	DBusMessageIter	iter, array_iter;
1867
1868	char *blob_name;
1869	const struct wpa_config_blob *blob;
1870
1871	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1872			      DBUS_TYPE_INVALID);
1873
1874	blob = wpa_config_get_blob(wpa_s->conf, blob_name);
1875	if (!blob) {
1876		return dbus_message_new_error(message,
1877					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1878					      "Blob id not set");
1879	}
1880
1881	reply = dbus_message_new_method_return(message);
1882	if (!reply) {
1883		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1884					       NULL);
1885		goto out;
1886	}
1887
1888	dbus_message_iter_init_append(reply, &iter);
1889
1890	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1891					      DBUS_TYPE_BYTE_AS_STRING,
1892					      &array_iter)) {
1893		dbus_message_unref(reply);
1894		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1895					       NULL);
1896		goto out;
1897	}
1898
1899	if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
1900						  &(blob->data), blob->len)) {
1901		dbus_message_unref(reply);
1902		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1903					       NULL);
1904		goto out;
1905	}
1906
1907	if (!dbus_message_iter_close_container(&iter, &array_iter)) {
1908		dbus_message_unref(reply);
1909		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1910					       NULL);
1911		goto out;
1912	}
1913
1914out:
1915	return reply;
1916}
1917
1918
1919/**
1920 * wpas_remove_handler_remove_blob - Remove named binary blob
1921 * @message: Pointer to incoming dbus message
1922 * @wpa_s: %wpa_supplicant data structure
1923 * Returns: NULL on success or dbus error
1924 *
1925 * Asks wpa_supplicant to internally remove a binary blobs.
1926 */
1927DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
1928					    struct wpa_supplicant *wpa_s)
1929{
1930	DBusMessage *reply = NULL;
1931	char *blob_name;
1932
1933	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1934			      DBUS_TYPE_INVALID);
1935
1936	if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
1937		return dbus_message_new_error(message,
1938					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1939					      "Blob id not set");
1940	}
1941	wpas_notify_blob_removed(wpa_s, blob_name);
1942
1943	return reply;
1944
1945}
1946
1947#endif /* CONFIG_NO_CONFIG_BLOBS */
1948
1949
1950/*
1951 * wpas_dbus_handler_flush_bss - Flush the BSS cache
1952 * @message: Pointer to incoming dbus message
1953 * @wpa_s: wpa_supplicant structure for a network interface
1954 * Returns: NULL
1955 *
1956 * Handler function for "FlushBSS" method call of network interface.
1957 */
1958DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
1959					  struct wpa_supplicant *wpa_s)
1960{
1961	dbus_uint32_t age;
1962
1963	dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
1964			      DBUS_TYPE_INVALID);
1965
1966	if (age == 0)
1967		wpa_bss_flush(wpa_s);
1968	else
1969		wpa_bss_flush_by_age(wpa_s, age);
1970
1971	return NULL;
1972}
1973
1974
1975#ifdef CONFIG_AUTOSCAN
1976/**
1977 * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
1978 * @message: Pointer to incoming dbus message
1979 * @wpa_s: wpa_supplicant structure for a network interface
1980 * Returns: NULL
1981 *
1982 * Handler function for "AutoScan" method call of network interface.
1983 */
1984DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
1985					 struct wpa_supplicant *wpa_s)
1986{
1987	DBusMessage *reply = NULL;
1988	enum wpa_states state = wpa_s->wpa_state;
1989	char *arg;
1990
1991	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
1992			      DBUS_TYPE_INVALID);
1993
1994	if (arg != NULL && os_strlen(arg) > 0) {
1995		char *tmp;
1996		tmp = os_strdup(arg);
1997		if (tmp == NULL) {
1998			reply = dbus_message_new_error(message,
1999						       DBUS_ERROR_NO_MEMORY,
2000						       NULL);
2001		} else {
2002			os_free(wpa_s->conf->autoscan);
2003			wpa_s->conf->autoscan = tmp;
2004			if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
2005				autoscan_init(wpa_s, 1);
2006			else if (state == WPA_SCANNING)
2007				wpa_supplicant_reinit_autoscan(wpa_s);
2008		}
2009	} else if (arg != NULL && os_strlen(arg) == 0) {
2010		os_free(wpa_s->conf->autoscan);
2011		wpa_s->conf->autoscan = NULL;
2012		autoscan_deinit(wpa_s);
2013	} else
2014		reply = dbus_message_new_error(message,
2015					       DBUS_ERROR_INVALID_ARGS,
2016					       NULL);
2017
2018	return reply;
2019}
2020#endif /* CONFIG_AUTOSCAN */
2021
2022
2023/*
2024 * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
2025 * @message: Pointer to incoming dbus message
2026 * @wpa_s: wpa_supplicant structure for a network interface
2027 * Returns: NULL
2028 *
2029 * Handler function for "EAPLogoff" method call of network interface.
2030 */
2031DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
2032					   struct wpa_supplicant *wpa_s)
2033{
2034	eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
2035	return NULL;
2036}
2037
2038
2039/*
2040 * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
2041 * @message: Pointer to incoming dbus message
2042 * @wpa_s: wpa_supplicant structure for a network interface
2043 * Returns: NULL
2044 *
2045 * Handler function for "EAPLogin" method call of network interface.
2046 */
2047DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
2048					  struct wpa_supplicant *wpa_s)
2049{
2050	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
2051	return NULL;
2052}
2053
2054
2055#ifdef CONFIG_TDLS
2056
2057static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
2058				  u8 *peer_address, DBusMessage **error)
2059{
2060	const char *peer_string;
2061
2062	*error = NULL;
2063
2064	if (!dbus_message_get_args(message, NULL,
2065				   DBUS_TYPE_STRING, &peer_string,
2066				   DBUS_TYPE_INVALID)) {
2067		*error = wpas_dbus_error_invalid_args(message, NULL);
2068		return -1;
2069	}
2070
2071	if (hwaddr_aton(peer_string, peer_address)) {
2072		wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
2073			   func_name, peer_string);
2074		*error = wpas_dbus_error_invalid_args(
2075			message, "Invalid hardware address format");
2076		return -1;
2077	}
2078
2079	return 0;
2080}
2081
2082
2083/*
2084 * wpas_dbus_handler_tdls_discover - Discover TDLS peer
2085 * @message: Pointer to incoming dbus message
2086 * @wpa_s: wpa_supplicant structure for a network interface
2087 * Returns: NULL indicating success or DBus error message on failure
2088 *
2089 * Handler function for "TDLSDiscover" method call of network interface.
2090 */
2091DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
2092					      struct wpa_supplicant *wpa_s)
2093{
2094	u8 peer[ETH_ALEN];
2095	DBusMessage *error_reply;
2096	int ret;
2097
2098	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2099		return error_reply;
2100
2101	wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
2102
2103	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2104		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
2105	else
2106		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
2107
2108	if (ret) {
2109		return wpas_dbus_error_unknown_error(
2110			message, "error performing TDLS discovery");
2111	}
2112
2113	return NULL;
2114}
2115
2116
2117/*
2118 * wpas_dbus_handler_tdls_setup - Setup TDLS session
2119 * @message: Pointer to incoming dbus message
2120 * @wpa_s: wpa_supplicant structure for a network interface
2121 * Returns: NULL indicating success or DBus error message on failure
2122 *
2123 * Handler function for "TDLSSetup" method call of network interface.
2124 */
2125DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
2126					   struct wpa_supplicant *wpa_s)
2127{
2128	u8 peer[ETH_ALEN];
2129	DBusMessage *error_reply;
2130	int ret;
2131
2132	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2133		return error_reply;
2134
2135	wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
2136
2137	wpa_tdls_remove(wpa_s->wpa, peer);
2138	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2139		ret = wpa_tdls_start(wpa_s->wpa, peer);
2140	else
2141		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2142
2143	if (ret) {
2144		return wpas_dbus_error_unknown_error(
2145			message, "error performing TDLS setup");
2146	}
2147
2148	return NULL;
2149}
2150
2151
2152/*
2153 * wpas_dbus_handler_tdls_status - Return TDLS session status
2154 * @message: Pointer to incoming dbus message
2155 * @wpa_s: wpa_supplicant structure for a network interface
2156 * Returns: A string representing the state of the link to this TDLS peer
2157 *
2158 * Handler function for "TDLSStatus" method call of network interface.
2159 */
2160DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
2161					    struct wpa_supplicant *wpa_s)
2162{
2163	u8 peer[ETH_ALEN];
2164	DBusMessage *reply;
2165	const char *tdls_status;
2166
2167	if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
2168		return reply;
2169
2170	wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
2171
2172	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
2173
2174	reply = dbus_message_new_method_return(message);
2175	dbus_message_append_args(reply, DBUS_TYPE_STRING,
2176				 &tdls_status, DBUS_TYPE_INVALID);
2177	return reply;
2178}
2179
2180
2181/*
2182 * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
2183 * @message: Pointer to incoming dbus message
2184 * @wpa_s: wpa_supplicant structure for a network interface
2185 * Returns: NULL indicating success or DBus error message on failure
2186 *
2187 * Handler function for "TDLSTeardown" method call of network interface.
2188 */
2189DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
2190					      struct wpa_supplicant *wpa_s)
2191{
2192	u8 peer[ETH_ALEN];
2193	DBusMessage *error_reply;
2194	int ret;
2195
2196	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2197		return error_reply;
2198
2199	wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
2200
2201	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2202		ret = wpa_tdls_teardown_link(
2203			wpa_s->wpa, peer,
2204			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
2205	else
2206		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
2207
2208	if (ret) {
2209		return wpas_dbus_error_unknown_error(
2210			message, "error performing TDLS teardown");
2211	}
2212
2213	return NULL;
2214}
2215
2216#endif /* CONFIG_TDLS */
2217
2218
2219/**
2220 * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
2221 * @message: Pointer to incoming dbus message
2222 * @wpa_s: %wpa_supplicant data structure
2223 * Returns: A dbus message containing an error on failure or NULL on success
2224 *
2225 * Sets the PKCS #11 engine and module path.
2226 */
2227DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
2228	DBusMessage *message, struct wpa_supplicant *wpa_s)
2229{
2230	DBusMessageIter iter;
2231	char *value = NULL;
2232	char *pkcs11_engine_path = NULL;
2233	char *pkcs11_module_path = NULL;
2234
2235	dbus_message_iter_init(message, &iter);
2236	dbus_message_iter_get_basic(&iter, &value);
2237	if (value == NULL) {
2238		return dbus_message_new_error(
2239			message, DBUS_ERROR_INVALID_ARGS,
2240			"Invalid pkcs11_engine_path argument");
2241	}
2242	/* Empty path defaults to NULL */
2243	if (os_strlen(value))
2244		pkcs11_engine_path = value;
2245
2246	dbus_message_iter_next(&iter);
2247	dbus_message_iter_get_basic(&iter, &value);
2248	if (value == NULL) {
2249		os_free(pkcs11_engine_path);
2250		return dbus_message_new_error(
2251			message, DBUS_ERROR_INVALID_ARGS,
2252			"Invalid pkcs11_module_path argument");
2253	}
2254	/* Empty path defaults to NULL */
2255	if (os_strlen(value))
2256		pkcs11_module_path = value;
2257
2258	if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
2259						   pkcs11_module_path))
2260		return dbus_message_new_error(
2261			message, DBUS_ERROR_FAILED,
2262			"Reinit of the EAPOL state machine with the new PKCS "
2263			"#11 engine and module path failed.");
2264
2265	wpa_dbus_mark_property_changed(
2266		wpa_s->global->dbus, wpa_s->dbus_new_path,
2267		WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
2268	wpa_dbus_mark_property_changed(
2269		wpa_s->global->dbus, wpa_s->dbus_new_path,
2270		WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
2271
2272	return NULL;
2273}
2274
2275
2276/**
2277 * wpas_dbus_getter_capabilities - Return interface capabilities
2278 * @iter: Pointer to incoming dbus message iter
2279 * @error: Location to store error on failure
2280 * @user_data: Function specific data
2281 * Returns: TRUE on success, FALSE on failure
2282 *
2283 * Getter for "Capabilities" property of an interface.
2284 */
2285dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
2286					  DBusError *error, void *user_data)
2287{
2288	struct wpa_supplicant *wpa_s = user_data;
2289	struct wpa_driver_capa capa;
2290	int res;
2291	DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
2292		variant_iter;
2293	const char *scans[] = { "active", "passive", "ssid" };
2294
2295	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
2296					      "a{sv}", &variant_iter))
2297		goto nomem;
2298
2299	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
2300		goto nomem;
2301
2302	res = wpa_drv_get_capa(wpa_s, &capa);
2303
2304	/***** pairwise cipher */
2305	if (res < 0) {
2306		const char *args[] = {"ccmp", "tkip", "none"};
2307		if (!wpa_dbus_dict_append_string_array(
2308			    &iter_dict, "Pairwise", args,
2309			    ARRAY_SIZE(args)))
2310			goto nomem;
2311	} else {
2312		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
2313						      &iter_dict_entry,
2314						      &iter_dict_val,
2315						      &iter_array))
2316			goto nomem;
2317
2318		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
2319			if (!wpa_dbus_dict_string_array_add_element(
2320				    &iter_array, "ccmp-256"))
2321				goto nomem;
2322		}
2323
2324		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
2325			if (!wpa_dbus_dict_string_array_add_element(
2326				    &iter_array, "gcmp-256"))
2327				goto nomem;
2328		}
2329
2330		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2331			if (!wpa_dbus_dict_string_array_add_element(
2332				    &iter_array, "ccmp"))
2333				goto nomem;
2334		}
2335
2336		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2337			if (!wpa_dbus_dict_string_array_add_element(
2338				    &iter_array, "gcmp"))
2339				goto nomem;
2340		}
2341
2342		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2343			if (!wpa_dbus_dict_string_array_add_element(
2344				    &iter_array, "tkip"))
2345				goto nomem;
2346		}
2347
2348		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2349			if (!wpa_dbus_dict_string_array_add_element(
2350				    &iter_array, "none"))
2351				goto nomem;
2352		}
2353
2354		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2355						    &iter_dict_entry,
2356						    &iter_dict_val,
2357						    &iter_array))
2358			goto nomem;
2359	}
2360
2361	/***** group cipher */
2362	if (res < 0) {
2363		const char *args[] = {
2364			"ccmp", "tkip", "wep104", "wep40"
2365		};
2366		if (!wpa_dbus_dict_append_string_array(
2367			    &iter_dict, "Group", args,
2368			    ARRAY_SIZE(args)))
2369			goto nomem;
2370	} else {
2371		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
2372						      &iter_dict_entry,
2373						      &iter_dict_val,
2374						      &iter_array))
2375			goto nomem;
2376
2377		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
2378			if (!wpa_dbus_dict_string_array_add_element(
2379				    &iter_array, "ccmp-256"))
2380				goto nomem;
2381		}
2382
2383		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
2384			if (!wpa_dbus_dict_string_array_add_element(
2385				    &iter_array, "gcmp-256"))
2386				goto nomem;
2387		}
2388
2389		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2390			if (!wpa_dbus_dict_string_array_add_element(
2391				    &iter_array, "ccmp"))
2392				goto nomem;
2393		}
2394
2395		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2396			if (!wpa_dbus_dict_string_array_add_element(
2397				    &iter_array, "gcmp"))
2398				goto nomem;
2399		}
2400
2401		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2402			if (!wpa_dbus_dict_string_array_add_element(
2403				    &iter_array, "tkip"))
2404				goto nomem;
2405		}
2406
2407		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
2408			if (!wpa_dbus_dict_string_array_add_element(
2409				    &iter_array, "wep104"))
2410				goto nomem;
2411		}
2412
2413		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
2414			if (!wpa_dbus_dict_string_array_add_element(
2415				    &iter_array, "wep40"))
2416				goto nomem;
2417		}
2418
2419		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2420						    &iter_dict_entry,
2421						    &iter_dict_val,
2422						    &iter_array))
2423			goto nomem;
2424	}
2425
2426	/***** key management */
2427	if (res < 0) {
2428		const char *args[] = {
2429			"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
2430#ifdef CONFIG_WPS
2431			"wps",
2432#endif /* CONFIG_WPS */
2433			"none"
2434		};
2435		if (!wpa_dbus_dict_append_string_array(
2436			    &iter_dict, "KeyMgmt", args,
2437			    ARRAY_SIZE(args)))
2438			goto nomem;
2439	} else {
2440		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
2441						      &iter_dict_entry,
2442						      &iter_dict_val,
2443						      &iter_array))
2444			goto nomem;
2445
2446		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2447							    "none"))
2448			goto nomem;
2449
2450		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2451							    "ieee8021x"))
2452			goto nomem;
2453
2454		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2455				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2456			if (!wpa_dbus_dict_string_array_add_element(
2457				    &iter_array, "wpa-eap"))
2458				goto nomem;
2459
2460			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
2461				if (!wpa_dbus_dict_string_array_add_element(
2462					    &iter_array, "wpa-ft-eap"))
2463					goto nomem;
2464
2465/* TODO: Ensure that driver actually supports sha256 encryption. */
2466#ifdef CONFIG_IEEE80211W
2467			if (!wpa_dbus_dict_string_array_add_element(
2468				    &iter_array, "wpa-eap-sha256"))
2469				goto nomem;
2470#endif /* CONFIG_IEEE80211W */
2471		}
2472
2473		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2474				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2475			if (!wpa_dbus_dict_string_array_add_element(
2476				    &iter_array, "wpa-psk"))
2477				goto nomem;
2478
2479			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
2480				if (!wpa_dbus_dict_string_array_add_element(
2481					    &iter_array, "wpa-ft-psk"))
2482					goto nomem;
2483
2484/* TODO: Ensure that driver actually supports sha256 encryption. */
2485#ifdef CONFIG_IEEE80211W
2486			if (!wpa_dbus_dict_string_array_add_element(
2487				    &iter_array, "wpa-psk-sha256"))
2488				goto nomem;
2489#endif /* CONFIG_IEEE80211W */
2490		}
2491
2492		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2493			if (!wpa_dbus_dict_string_array_add_element(
2494				    &iter_array, "wpa-none"))
2495				goto nomem;
2496		}
2497
2498
2499#ifdef CONFIG_WPS
2500		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2501							    "wps"))
2502			goto nomem;
2503#endif /* CONFIG_WPS */
2504
2505		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2506						    &iter_dict_entry,
2507						    &iter_dict_val,
2508						    &iter_array))
2509			goto nomem;
2510	}
2511
2512	/***** WPA protocol */
2513	if (res < 0) {
2514		const char *args[] = { "rsn", "wpa" };
2515		if (!wpa_dbus_dict_append_string_array(
2516			    &iter_dict, "Protocol", args,
2517			    ARRAY_SIZE(args)))
2518			goto nomem;
2519	} else {
2520		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
2521						      &iter_dict_entry,
2522						      &iter_dict_val,
2523						      &iter_array))
2524			goto nomem;
2525
2526		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2527				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2528			if (!wpa_dbus_dict_string_array_add_element(
2529				    &iter_array, "rsn"))
2530				goto nomem;
2531		}
2532
2533		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2534				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
2535			if (!wpa_dbus_dict_string_array_add_element(
2536				    &iter_array, "wpa"))
2537				goto nomem;
2538		}
2539
2540		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2541						    &iter_dict_entry,
2542						    &iter_dict_val,
2543						    &iter_array))
2544			goto nomem;
2545	}
2546
2547	/***** auth alg */
2548	if (res < 0) {
2549		const char *args[] = { "open", "shared", "leap" };
2550		if (!wpa_dbus_dict_append_string_array(
2551			    &iter_dict, "AuthAlg", args,
2552			    ARRAY_SIZE(args)))
2553			goto nomem;
2554	} else {
2555		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
2556						      &iter_dict_entry,
2557						      &iter_dict_val,
2558						      &iter_array))
2559			goto nomem;
2560
2561		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
2562			if (!wpa_dbus_dict_string_array_add_element(
2563				    &iter_array, "open"))
2564				goto nomem;
2565		}
2566
2567		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
2568			if (!wpa_dbus_dict_string_array_add_element(
2569				    &iter_array, "shared"))
2570				goto nomem;
2571		}
2572
2573		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
2574			if (!wpa_dbus_dict_string_array_add_element(
2575				    &iter_array, "leap"))
2576				goto nomem;
2577		}
2578
2579		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2580						    &iter_dict_entry,
2581						    &iter_dict_val,
2582						    &iter_array))
2583			goto nomem;
2584	}
2585
2586	/***** Scan */
2587	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
2588					       ARRAY_SIZE(scans)))
2589		goto nomem;
2590
2591	/***** Modes */
2592	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
2593					      &iter_dict_entry,
2594					      &iter_dict_val,
2595					      &iter_array))
2596		goto nomem;
2597
2598	if (!wpa_dbus_dict_string_array_add_element(
2599			    &iter_array, "infrastructure"))
2600		goto nomem;
2601
2602	if (!wpa_dbus_dict_string_array_add_element(
2603			    &iter_array, "ad-hoc"))
2604		goto nomem;
2605
2606	if (res >= 0) {
2607		if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
2608			if (!wpa_dbus_dict_string_array_add_element(
2609				    &iter_array, "ap"))
2610				goto nomem;
2611		}
2612
2613		if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
2614			if (!wpa_dbus_dict_string_array_add_element(
2615				    &iter_array, "p2p"))
2616				goto nomem;
2617		}
2618	}
2619
2620	if (!wpa_dbus_dict_end_string_array(&iter_dict,
2621					    &iter_dict_entry,
2622					    &iter_dict_val,
2623					    &iter_array))
2624		goto nomem;
2625	/***** Modes end */
2626
2627	if (res >= 0) {
2628		dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
2629
2630		if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
2631						max_scan_ssid))
2632			goto nomem;
2633	}
2634
2635	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
2636		goto nomem;
2637	if (!dbus_message_iter_close_container(iter, &variant_iter))
2638		goto nomem;
2639
2640	return TRUE;
2641
2642nomem:
2643	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2644	return FALSE;
2645}
2646
2647
2648/**
2649 * wpas_dbus_getter_state - Get interface state
2650 * @iter: Pointer to incoming dbus message iter
2651 * @error: Location to store error on failure
2652 * @user_data: Function specific data
2653 * Returns: TRUE on success, FALSE on failure
2654 *
2655 * Getter for "State" property.
2656 */
2657dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
2658				   void *user_data)
2659{
2660	struct wpa_supplicant *wpa_s = user_data;
2661	const char *str_state;
2662	char *state_ls, *tmp;
2663	dbus_bool_t success = FALSE;
2664
2665	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
2666
2667	/* make state string lowercase to fit new DBus API convention
2668	 */
2669	state_ls = tmp = os_strdup(str_state);
2670	if (!tmp) {
2671		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2672		return FALSE;
2673	}
2674	while (*tmp) {
2675		*tmp = tolower(*tmp);
2676		tmp++;
2677	}
2678
2679	success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2680						   &state_ls, error);
2681
2682	os_free(state_ls);
2683
2684	return success;
2685}
2686
2687
2688/**
2689 * wpas_dbus_new_iface_get_scanning - Get interface scanning state
2690 * @iter: Pointer to incoming dbus message iter
2691 * @error: Location to store error on failure
2692 * @user_data: Function specific data
2693 * Returns: TRUE on success, FALSE on failure
2694 *
2695 * Getter for "scanning" property.
2696 */
2697dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
2698                                      void *user_data)
2699{
2700	struct wpa_supplicant *wpa_s = user_data;
2701	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
2702
2703	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2704						&scanning, error);
2705}
2706
2707
2708/**
2709 * wpas_dbus_getter_ap_scan - Control roaming mode
2710 * @iter: Pointer to incoming dbus message iter
2711 * @error: Location to store error on failure
2712 * @user_data: Function specific data
2713 * Returns: TRUE on success, FALSE on failure
2714 *
2715 * Getter function for "ApScan" property.
2716 */
2717dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
2718				     void *user_data)
2719{
2720	struct wpa_supplicant *wpa_s = user_data;
2721	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
2722
2723	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2724						&ap_scan, error);
2725}
2726
2727
2728/**
2729 * wpas_dbus_setter_ap_scan - Control roaming mode
2730 * @iter: Pointer to incoming dbus message iter
2731 * @error: Location to store error on failure
2732 * @user_data: Function specific data
2733 * Returns: TRUE on success, FALSE on failure
2734 *
2735 * Setter function for "ApScan" property.
2736 */
2737dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
2738				     void *user_data)
2739{
2740	struct wpa_supplicant *wpa_s = user_data;
2741	dbus_uint32_t ap_scan;
2742
2743	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2744					      &ap_scan))
2745		return FALSE;
2746
2747	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
2748		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2749				     "ap_scan must be 0, 1, or 2");
2750		return FALSE;
2751	}
2752	return TRUE;
2753}
2754
2755
2756/**
2757 * wpas_dbus_getter_fast_reauth - Control fast
2758 * reauthentication (TLS session resumption)
2759 * @iter: Pointer to incoming dbus message iter
2760 * @error: Location to store error on failure
2761 * @user_data: Function specific data
2762 * Returns: TRUE on success, FALSE on failure
2763 *
2764 * Getter function for "FastReauth" property.
2765 */
2766dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
2767					 DBusError *error,
2768					 void *user_data)
2769{
2770	struct wpa_supplicant *wpa_s = user_data;
2771	dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
2772
2773	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2774						&fast_reauth, error);
2775}
2776
2777
2778/**
2779 * wpas_dbus_setter_fast_reauth - Control fast
2780 * reauthentication (TLS session resumption)
2781 * @iter: Pointer to incoming dbus message iter
2782 * @error: Location to store error on failure
2783 * @user_data: Function specific data
2784 * Returns: TRUE on success, FALSE on failure
2785 *
2786 * Setter function for "FastReauth" property.
2787 */
2788dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
2789				     DBusError *error,
2790				     void *user_data)
2791{
2792	struct wpa_supplicant *wpa_s = user_data;
2793	dbus_bool_t fast_reauth;
2794
2795	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
2796					      &fast_reauth))
2797		return FALSE;
2798
2799	wpa_s->conf->fast_reauth = fast_reauth;
2800	return TRUE;
2801}
2802
2803
2804/**
2805 * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
2806 * @iter: Pointer to incoming dbus message iter
2807 * @error: Location to store error on failure
2808 * @user_data: Function specific data
2809 * Returns: TRUE on success, FALSE on failure
2810 *
2811 * Getter for "DisconnectReason" property.  The reason is negative if it is
2812 * locally generated.
2813 */
2814dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
2815					       DBusError *error,
2816					       void *user_data)
2817{
2818	struct wpa_supplicant *wpa_s = user_data;
2819	dbus_int32_t reason = wpa_s->disconnect_reason;
2820	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
2821						&reason, error);
2822}
2823
2824
2825/**
2826 * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
2827 * @iter: Pointer to incoming dbus message iter
2828 * @error: Location to store error on failure
2829 * @user_data: Function specific data
2830 * Returns: TRUE on success, FALSE on failure
2831 *
2832 * Getter function for "BSSExpireAge" property.
2833 */
2834dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
2835					    DBusError *error,
2836					    void *user_data)
2837{
2838	struct wpa_supplicant *wpa_s = user_data;
2839	dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
2840
2841	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2842						&expire_age, error);
2843}
2844
2845
2846/**
2847 * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
2848 * @iter: Pointer to incoming dbus message iter
2849 * @error: Location to store error on failure
2850 * @user_data: Function specific data
2851 * Returns: TRUE on success, FALSE on failure
2852 *
2853 * Setter function for "BSSExpireAge" property.
2854 */
2855dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
2856					    DBusError *error,
2857					    void *user_data)
2858{
2859	struct wpa_supplicant *wpa_s = user_data;
2860	dbus_uint32_t expire_age;
2861
2862	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2863					      &expire_age))
2864		return FALSE;
2865
2866	if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
2867		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2868				     "BSSExpireAge must be >= 10");
2869		return FALSE;
2870	}
2871	return TRUE;
2872}
2873
2874
2875/**
2876 * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
2877 * @iter: Pointer to incoming dbus message iter
2878 * @error: Location to store error on failure
2879 * @user_data: Function specific data
2880 * Returns: TRUE on success, FALSE on failure
2881 *
2882 * Getter function for "BSSExpireCount" property.
2883 */
2884dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
2885					      DBusError *error,
2886					      void *user_data)
2887{
2888	struct wpa_supplicant *wpa_s = user_data;
2889	dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
2890
2891	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2892						&expire_count, error);
2893}
2894
2895
2896/**
2897 * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
2898 * @iter: Pointer to incoming dbus message iter
2899 * @error: Location to store error on failure
2900 * @user_data: Function specific data
2901 * Returns: TRUE on success, FALSE on failure
2902 *
2903 * Setter function for "BSSExpireCount" property.
2904 */
2905dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
2906					      DBusError *error,
2907					      void *user_data)
2908{
2909	struct wpa_supplicant *wpa_s = user_data;
2910	dbus_uint32_t expire_count;
2911
2912	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2913					      &expire_count))
2914		return FALSE;
2915
2916	if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
2917		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2918				     "BSSExpireCount must be > 0");
2919		return FALSE;
2920	}
2921	return TRUE;
2922}
2923
2924
2925/**
2926 * wpas_dbus_getter_country - Control country code
2927 * @iter: Pointer to incoming dbus message iter
2928 * @error: Location to store error on failure
2929 * @user_data: Function specific data
2930 * Returns: TRUE on success, FALSE on failure
2931 *
2932 * Getter function for "Country" property.
2933 */
2934dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
2935				     void *user_data)
2936{
2937	struct wpa_supplicant *wpa_s = user_data;
2938	char country[3];
2939	char *str = country;
2940
2941	country[0] = wpa_s->conf->country[0];
2942	country[1] = wpa_s->conf->country[1];
2943	country[2] = '\0';
2944
2945	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2946						&str, error);
2947}
2948
2949
2950/**
2951 * wpas_dbus_setter_country - Control country code
2952 * @iter: Pointer to incoming dbus message iter
2953 * @error: Location to store error on failure
2954 * @user_data: Function specific data
2955 * Returns: TRUE on success, FALSE on failure
2956 *
2957 * Setter function for "Country" property.
2958 */
2959dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
2960				     void *user_data)
2961{
2962	struct wpa_supplicant *wpa_s = user_data;
2963	const char *country;
2964
2965	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
2966					      &country))
2967		return FALSE;
2968
2969	if (!country[0] || !country[1]) {
2970		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2971				     "invalid country code");
2972		return FALSE;
2973	}
2974
2975	if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
2976		wpa_printf(MSG_DEBUG, "Failed to set country");
2977		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2978				     "failed to set country code");
2979		return FALSE;
2980	}
2981
2982	wpa_s->conf->country[0] = country[0];
2983	wpa_s->conf->country[1] = country[1];
2984	return TRUE;
2985}
2986
2987
2988/**
2989 * wpas_dbus_getter_scan_interval - Get scan interval
2990 * @iter: Pointer to incoming dbus message iter
2991 * @error: Location to store error on failure
2992 * @user_data: Function specific data
2993 * Returns: TRUE on success, FALSE on failure
2994 *
2995 * Getter function for "ScanInterval" property.
2996 */
2997dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
2998					   DBusError *error,
2999					   void *user_data)
3000{
3001	struct wpa_supplicant *wpa_s = user_data;
3002	dbus_int32_t scan_interval = wpa_s->scan_interval;
3003
3004	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3005						&scan_interval, error);
3006}
3007
3008
3009/**
3010 * wpas_dbus_setter_scan_interval - Control scan interval
3011 * @iter: Pointer to incoming dbus message iter
3012 * @error: Location to store error on failure
3013 * @user_data: Function specific data
3014 * Returns: TRUE on success, FALSE on failure
3015 *
3016 * Setter function for "ScanInterval" property.
3017 */
3018dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
3019					   DBusError *error,
3020					   void *user_data)
3021{
3022	struct wpa_supplicant *wpa_s = user_data;
3023	dbus_int32_t scan_interval;
3024
3025	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
3026					      &scan_interval))
3027		return FALSE;
3028
3029	if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
3030		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3031				     "scan_interval must be >= 0");
3032		return FALSE;
3033	}
3034	return TRUE;
3035}
3036
3037
3038/**
3039 * wpas_dbus_getter_ifname - Get interface name
3040 * @iter: Pointer to incoming dbus message iter
3041 * @error: Location to store error on failure
3042 * @user_data: Function specific data
3043 * Returns: TRUE on success, FALSE on failure
3044 *
3045 * Getter for "Ifname" property.
3046 */
3047dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
3048				    void *user_data)
3049{
3050	struct wpa_supplicant *wpa_s = user_data;
3051	const char *ifname = wpa_s->ifname;
3052
3053	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3054						&ifname, error);
3055}
3056
3057
3058/**
3059 * wpas_dbus_getter_driver - Get interface name
3060 * @iter: Pointer to incoming dbus message iter
3061 * @error: Location to store error on failure
3062 * @user_data: Function specific data
3063 * Returns: TRUE on success, FALSE on failure
3064 *
3065 * Getter for "Driver" property.
3066 */
3067dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
3068				    void *user_data)
3069{
3070	struct wpa_supplicant *wpa_s = user_data;
3071	const char *driver;
3072
3073	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
3074		wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
3075			   "wpa_s has no driver set");
3076		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
3077			       __func__);
3078		return FALSE;
3079	}
3080
3081	driver = wpa_s->driver->name;
3082	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3083						&driver, error);
3084}
3085
3086
3087/**
3088 * wpas_dbus_getter_current_bss - Get current bss object path
3089 * @iter: Pointer to incoming dbus message iter
3090 * @error: Location to store error on failure
3091 * @user_data: Function specific data
3092 * Returns: TRUE on success, FALSE on failure
3093 *
3094 * Getter for "CurrentBSS" property.
3095 */
3096dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
3097					 DBusError *error,
3098					 void *user_data)
3099{
3100	struct wpa_supplicant *wpa_s = user_data;
3101	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
3102
3103	if (wpa_s->current_bss)
3104		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3105			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3106			    wpa_s->dbus_new_path, wpa_s->current_bss->id);
3107	else
3108		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3109
3110	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3111						&bss_obj_path, error);
3112}
3113
3114
3115/**
3116 * wpas_dbus_getter_current_network - Get current network object path
3117 * @iter: Pointer to incoming dbus message iter
3118 * @error: Location to store error on failure
3119 * @user_data: Function specific data
3120 * Returns: TRUE on success, FALSE on failure
3121 *
3122 * Getter for "CurrentNetwork" property.
3123 */
3124dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
3125					     DBusError *error,
3126					     void *user_data)
3127{
3128	struct wpa_supplicant *wpa_s = user_data;
3129	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
3130
3131	if (wpa_s->current_ssid)
3132		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3133			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
3134			    wpa_s->dbus_new_path, wpa_s->current_ssid->id);
3135	else
3136		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3137
3138	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3139						&net_obj_path, error);
3140}
3141
3142
3143/**
3144 * wpas_dbus_getter_current_auth_mode - Get current authentication type
3145 * @iter: Pointer to incoming dbus message iter
3146 * @error: Location to store error on failure
3147 * @user_data: Function specific data
3148 * Returns: TRUE on success, FALSE on failure
3149 *
3150 * Getter for "CurrentAuthMode" property.
3151 */
3152dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
3153					       DBusError *error,
3154					       void *user_data)
3155{
3156	struct wpa_supplicant *wpa_s = user_data;
3157	const char *eap_mode;
3158	const char *auth_mode;
3159	char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
3160
3161	if (wpa_s->wpa_state != WPA_COMPLETED) {
3162		auth_mode = "INACTIVE";
3163	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
3164	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3165		eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
3166		os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
3167			    "EAP-%s", eap_mode);
3168		auth_mode = eap_mode_buf;
3169
3170	} else {
3171		auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
3172					     wpa_s->current_ssid->proto);
3173	}
3174
3175	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3176						&auth_mode, error);
3177}
3178
3179
3180/**
3181 * wpas_dbus_getter_bridge_ifname - Get interface name
3182 * @iter: Pointer to incoming dbus message iter
3183 * @error: Location to store error on failure
3184 * @user_data: Function specific data
3185 * Returns: TRUE on success, FALSE on failure
3186 *
3187 * Getter for "BridgeIfname" property.
3188 */
3189dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
3190					   DBusError *error,
3191					   void *user_data)
3192{
3193	struct wpa_supplicant *wpa_s = user_data;
3194	const char *bridge_ifname = wpa_s->bridge_ifname;
3195	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3196						&bridge_ifname, error);
3197}
3198
3199
3200/**
3201 * wpas_dbus_getter_bsss - Get array of BSSs objects
3202 * @iter: Pointer to incoming dbus message iter
3203 * @error: Location to store error on failure
3204 * @user_data: Function specific data
3205 * Returns: TRUE on success, FALSE on failure
3206 *
3207 * Getter for "BSSs" property.
3208 */
3209dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
3210				  void *user_data)
3211{
3212	struct wpa_supplicant *wpa_s = user_data;
3213	struct wpa_bss *bss;
3214	char **paths;
3215	unsigned int i = 0;
3216	dbus_bool_t success = FALSE;
3217
3218	paths = os_calloc(wpa_s->num_bss, sizeof(char *));
3219	if (!paths) {
3220		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3221		return FALSE;
3222	}
3223
3224	/* Loop through scan results and append each result's object path */
3225	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
3226		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3227		if (paths[i] == NULL) {
3228			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3229					     "no memory");
3230			goto out;
3231		}
3232		/* Construct the object path for this BSS. */
3233		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3234			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3235			    wpa_s->dbus_new_path, bss->id);
3236	}
3237
3238	success = wpas_dbus_simple_array_property_getter(iter,
3239							 DBUS_TYPE_OBJECT_PATH,
3240							 paths, wpa_s->num_bss,
3241							 error);
3242
3243out:
3244	while (i)
3245		os_free(paths[--i]);
3246	os_free(paths);
3247	return success;
3248}
3249
3250
3251/**
3252 * wpas_dbus_getter_networks - Get array of networks objects
3253 * @iter: Pointer to incoming dbus message iter
3254 * @error: Location to store error on failure
3255 * @user_data: Function specific data
3256 * Returns: TRUE on success, FALSE on failure
3257 *
3258 * Getter for "Networks" property.
3259 */
3260dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
3261				      void *user_data)
3262{
3263	struct wpa_supplicant *wpa_s = user_data;
3264	struct wpa_ssid *ssid;
3265	char **paths;
3266	unsigned int i = 0, num = 0;
3267	dbus_bool_t success = FALSE;
3268
3269	if (wpa_s->conf == NULL) {
3270		wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
3271			   "networks list.", __func__);
3272		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
3273			       "occurred getting the networks list", __func__);
3274		return FALSE;
3275	}
3276
3277	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
3278		if (!network_is_persistent_group(ssid))
3279			num++;
3280
3281	paths = os_calloc(num, sizeof(char *));
3282	if (!paths) {
3283		dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3284		return FALSE;
3285	}
3286
3287	/* Loop through configured networks and append object path of each */
3288	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
3289		if (network_is_persistent_group(ssid))
3290			continue;
3291		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3292		if (paths[i] == NULL) {
3293			dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3294			goto out;
3295		}
3296
3297		/* Construct the object path for this network. */
3298		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3299			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
3300			    wpa_s->dbus_new_path, ssid->id);
3301	}
3302
3303	success = wpas_dbus_simple_array_property_getter(iter,
3304							 DBUS_TYPE_OBJECT_PATH,
3305							 paths, num, error);
3306
3307out:
3308	while (i)
3309		os_free(paths[--i]);
3310	os_free(paths);
3311	return success;
3312}
3313
3314
3315/**
3316 * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
3317 * @iter: Pointer to incoming dbus message iter
3318 * @error: Location to store error on failure
3319 * @user_data: Function specific data
3320 * Returns: A dbus message containing the PKCS #11 engine path
3321 *
3322 * Getter for "PKCS11EnginePath" property.
3323 */
3324dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
3325						DBusError *error,
3326						void *user_data)
3327{
3328	struct wpa_supplicant *wpa_s = user_data;
3329	const char *pkcs11_engine_path;
3330
3331	if (wpa_s->conf == NULL) {
3332		wpa_printf(MSG_ERROR,
3333			   "wpas_dbus_getter_pkcs11_engine_path[dbus]: An "
3334			   "error occurred getting the PKCS #11 engine path.");
3335		dbus_set_error_const(
3336			error, DBUS_ERROR_FAILED,
3337			"An error occured getting the PKCS #11 engine path.");
3338		return FALSE;
3339	}
3340
3341	if (wpa_s->conf->pkcs11_engine_path == NULL)
3342		pkcs11_engine_path = "";
3343	else
3344		pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
3345	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3346						&pkcs11_engine_path, error);
3347}
3348
3349
3350/**
3351 * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
3352 * @iter: Pointer to incoming dbus message iter
3353 * @error: Location to store error on failure
3354 * @user_data: Function specific data
3355 * Returns: A dbus message containing the PKCS #11 module path
3356 *
3357 * Getter for "PKCS11ModulePath" property.
3358 */
3359dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
3360						DBusError *error,
3361						void *user_data)
3362{
3363	struct wpa_supplicant *wpa_s = user_data;
3364	const char *pkcs11_module_path;
3365
3366	if (wpa_s->conf == NULL) {
3367		wpa_printf(MSG_ERROR,
3368			   "wpas_dbus_getter_pkcs11_module_path[dbus]: An "
3369			   "error occurred getting the PKCS #11 module path.");
3370		dbus_set_error_const(
3371			error, DBUS_ERROR_FAILED,
3372			"An error occured getting the PKCS #11 module path.");
3373		return FALSE;
3374	}
3375
3376	if (wpa_s->conf->pkcs11_module_path == NULL)
3377		pkcs11_module_path = "";
3378	else
3379		pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
3380	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3381						&pkcs11_module_path, error);
3382}
3383
3384
3385/**
3386 * wpas_dbus_getter_blobs - Get all blobs defined for this interface
3387 * @iter: Pointer to incoming dbus message iter
3388 * @error: Location to store error on failure
3389 * @user_data: Function specific data
3390 * Returns: TRUE on success, FALSE on failure
3391 *
3392 * Getter for "Blobs" property.
3393 */
3394dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
3395				   void *user_data)
3396{
3397	struct wpa_supplicant *wpa_s = user_data;
3398	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
3399	struct wpa_config_blob *blob;
3400
3401	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3402					      "a{say}", &variant_iter) ||
3403	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
3404					      "{say}", &dict_iter)) {
3405		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3406		return FALSE;
3407	}
3408
3409	blob = wpa_s->conf->blobs;
3410	while (blob) {
3411		if (!dbus_message_iter_open_container(&dict_iter,
3412						      DBUS_TYPE_DICT_ENTRY,
3413						      NULL, &entry_iter) ||
3414		    !dbus_message_iter_append_basic(&entry_iter,
3415						    DBUS_TYPE_STRING,
3416						    &(blob->name)) ||
3417		    !dbus_message_iter_open_container(&entry_iter,
3418						      DBUS_TYPE_ARRAY,
3419						      DBUS_TYPE_BYTE_AS_STRING,
3420						      &array_iter) ||
3421		    !dbus_message_iter_append_fixed_array(&array_iter,
3422							  DBUS_TYPE_BYTE,
3423							  &(blob->data),
3424							  blob->len) ||
3425		    !dbus_message_iter_close_container(&entry_iter,
3426						       &array_iter) ||
3427		    !dbus_message_iter_close_container(&dict_iter,
3428						       &entry_iter)) {
3429			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3430					     "no memory");
3431			return FALSE;
3432		}
3433
3434		blob = blob->next;
3435	}
3436
3437	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
3438	    !dbus_message_iter_close_container(iter, &variant_iter)) {
3439		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3440		return FALSE;
3441	}
3442
3443	return TRUE;
3444}
3445
3446
3447static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
3448				       DBusError *error, const char *func_name)
3449{
3450	struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
3451
3452	if (!res) {
3453		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
3454		           func_name, args->id);
3455		dbus_set_error(error, DBUS_ERROR_FAILED,
3456			       "%s: BSS %d not found",
3457			       func_name, args->id);
3458	}
3459
3460	return res;
3461}
3462
3463
3464/**
3465 * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
3466 * @iter: Pointer to incoming dbus message iter
3467 * @error: Location to store error on failure
3468 * @user_data: Function specific data
3469 * Returns: TRUE on success, FALSE on failure
3470 *
3471 * Getter for "BSSID" property.
3472 */
3473dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
3474				       void *user_data)
3475{
3476	struct bss_handler_args *args = user_data;
3477	struct wpa_bss *res;
3478
3479	res = get_bss_helper(args, error, __func__);
3480	if (!res)
3481		return FALSE;
3482
3483	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3484						      res->bssid, ETH_ALEN,
3485						      error);
3486}
3487
3488
3489/**
3490 * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
3491 * @iter: Pointer to incoming dbus message iter
3492 * @error: Location to store error on failure
3493 * @user_data: Function specific data
3494 * Returns: TRUE on success, FALSE on failure
3495 *
3496 * Getter for "SSID" property.
3497 */
3498dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
3499				      void *user_data)
3500{
3501	struct bss_handler_args *args = user_data;
3502	struct wpa_bss *res;
3503
3504	res = get_bss_helper(args, error, __func__);
3505	if (!res)
3506		return FALSE;
3507
3508	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3509						      res->ssid, res->ssid_len,
3510						      error);
3511}
3512
3513
3514/**
3515 * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
3516 * @iter: Pointer to incoming dbus message iter
3517 * @error: Location to store error on failure
3518 * @user_data: Function specific data
3519 * Returns: TRUE on success, FALSE on failure
3520 *
3521 * Getter for "Privacy" property.
3522 */
3523dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
3524					 DBusError *error, void *user_data)
3525{
3526	struct bss_handler_args *args = user_data;
3527	struct wpa_bss *res;
3528	dbus_bool_t privacy;
3529
3530	res = get_bss_helper(args, error, __func__);
3531	if (!res)
3532		return FALSE;
3533
3534	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
3535	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3536						&privacy, error);
3537}
3538
3539
3540/**
3541 * wpas_dbus_getter_bss_mode - Return the mode of a BSS
3542 * @iter: Pointer to incoming dbus message iter
3543 * @error: Location to store error on failure
3544 * @user_data: Function specific data
3545 * Returns: TRUE on success, FALSE on failure
3546 *
3547 * Getter for "Mode" property.
3548 */
3549dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
3550				      void *user_data)
3551{
3552	struct bss_handler_args *args = user_data;
3553	struct wpa_bss *res;
3554	const char *mode;
3555
3556	res = get_bss_helper(args, error, __func__);
3557	if (!res)
3558		return FALSE;
3559	if (bss_is_dmg(res)) {
3560		switch (res->caps & IEEE80211_CAP_DMG_MASK) {
3561		case IEEE80211_CAP_DMG_PBSS:
3562		case IEEE80211_CAP_DMG_IBSS:
3563			mode = "ad-hoc";
3564			break;
3565		case IEEE80211_CAP_DMG_AP:
3566			mode = "infrastructure";
3567			break;
3568		}
3569	} else {
3570		if (res->caps & IEEE80211_CAP_IBSS)
3571			mode = "ad-hoc";
3572		else
3573			mode = "infrastructure";
3574	}
3575
3576	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3577						&mode, error);
3578}
3579
3580
3581/**
3582 * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
3583 * @iter: Pointer to incoming dbus message iter
3584 * @error: Location to store error on failure
3585 * @user_data: Function specific data
3586 * Returns: TRUE on success, FALSE on failure
3587 *
3588 * Getter for "Level" property.
3589 */
3590dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
3591					DBusError *error, void *user_data)
3592{
3593	struct bss_handler_args *args = user_data;
3594	struct wpa_bss *res;
3595	s16 level;
3596
3597	res = get_bss_helper(args, error, __func__);
3598	if (!res)
3599		return FALSE;
3600
3601	level = (s16) res->level;
3602	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
3603						&level, error);
3604}
3605
3606
3607/**
3608 * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
3609 * @iter: Pointer to incoming dbus message iter
3610 * @error: Location to store error on failure
3611 * @user_data: Function specific data
3612 * Returns: TRUE on success, FALSE on failure
3613 *
3614 * Getter for "Frequency" property.
3615 */
3616dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
3617					   DBusError *error, void *user_data)
3618{
3619	struct bss_handler_args *args = user_data;
3620	struct wpa_bss *res;
3621	u16 freq;
3622
3623	res = get_bss_helper(args, error, __func__);
3624	if (!res)
3625		return FALSE;
3626
3627	freq = (u16) res->freq;
3628	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
3629						&freq, error);
3630}
3631
3632
3633static int cmp_u8s_desc(const void *a, const void *b)
3634{
3635	return (*(u8 *) b - *(u8 *) a);
3636}
3637
3638
3639/**
3640 * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
3641 * @iter: Pointer to incoming dbus message iter
3642 * @error: Location to store error on failure
3643 * @user_data: Function specific data
3644 * Returns: TRUE on success, FALSE on failure
3645 *
3646 * Getter for "Rates" property.
3647 */
3648dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
3649				       DBusError *error, void *user_data)
3650{
3651	struct bss_handler_args *args = user_data;
3652	struct wpa_bss *res;
3653	u8 *ie_rates = NULL;
3654	u32 *real_rates;
3655	int rates_num, i;
3656	dbus_bool_t success = FALSE;
3657
3658	res = get_bss_helper(args, error, __func__);
3659	if (!res)
3660		return FALSE;
3661
3662	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
3663	if (rates_num < 0)
3664		return FALSE;
3665
3666	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
3667
3668	real_rates = os_malloc(sizeof(u32) * rates_num);
3669	if (!real_rates) {
3670		os_free(ie_rates);
3671		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3672		return FALSE;
3673	}
3674
3675	for (i = 0; i < rates_num; i++)
3676		real_rates[i] = ie_rates[i] * 500000;
3677
3678	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
3679							 real_rates, rates_num,
3680							 error);
3681
3682	os_free(ie_rates);
3683	os_free(real_rates);
3684	return success;
3685}
3686
3687
3688static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
3689						   struct wpa_ie_data *ie_data,
3690						   DBusError *error)
3691{
3692	DBusMessageIter iter_dict, variant_iter;
3693	const char *group;
3694	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
3695	const char *key_mgmt[7]; /* max 7 key managements may be supported */
3696	int n;
3697
3698	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3699					      "a{sv}", &variant_iter))
3700		goto nomem;
3701
3702	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3703		goto nomem;
3704
3705	/* KeyMgmt */
3706	n = 0;
3707	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
3708		key_mgmt[n++] = "wpa-psk";
3709	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
3710		key_mgmt[n++] = "wpa-ft-psk";
3711	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
3712		key_mgmt[n++] = "wpa-psk-sha256";
3713	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
3714		key_mgmt[n++] = "wpa-eap";
3715	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
3716		key_mgmt[n++] = "wpa-ft-eap";
3717	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
3718		key_mgmt[n++] = "wpa-eap-sha256";
3719	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
3720		key_mgmt[n++] = "wpa-none";
3721
3722	if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
3723					       key_mgmt, n))
3724		goto nomem;
3725
3726	/* Group */
3727	switch (ie_data->group_cipher) {
3728	case WPA_CIPHER_WEP40:
3729		group = "wep40";
3730		break;
3731	case WPA_CIPHER_TKIP:
3732		group = "tkip";
3733		break;
3734	case WPA_CIPHER_CCMP:
3735		group = "ccmp";
3736		break;
3737	case WPA_CIPHER_GCMP:
3738		group = "gcmp";
3739		break;
3740	case WPA_CIPHER_WEP104:
3741		group = "wep104";
3742		break;
3743	case WPA_CIPHER_CCMP_256:
3744		group = "ccmp-256";
3745		break;
3746	case WPA_CIPHER_GCMP_256:
3747		group = "gcmp-256";
3748		break;
3749	default:
3750		group = "";
3751		break;
3752	}
3753
3754	if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
3755		goto nomem;
3756
3757	/* Pairwise */
3758	n = 0;
3759	if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
3760		pairwise[n++] = "tkip";
3761	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
3762		pairwise[n++] = "ccmp";
3763	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
3764		pairwise[n++] = "gcmp";
3765	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
3766		pairwise[n++] = "ccmp-256";
3767	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
3768		pairwise[n++] = "gcmp-256";
3769
3770	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
3771					       pairwise, n))
3772		goto nomem;
3773
3774	/* Management group (RSN only) */
3775	if (ie_data->proto == WPA_PROTO_RSN) {
3776		switch (ie_data->mgmt_group_cipher) {
3777#ifdef CONFIG_IEEE80211W
3778		case WPA_CIPHER_AES_128_CMAC:
3779			group = "aes128cmac";
3780			break;
3781#endif /* CONFIG_IEEE80211W */
3782		default:
3783			group = "";
3784			break;
3785		}
3786
3787		if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
3788						 group))
3789			goto nomem;
3790	}
3791
3792	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
3793		goto nomem;
3794	if (!dbus_message_iter_close_container(iter, &variant_iter))
3795		goto nomem;
3796
3797	return TRUE;
3798
3799nomem:
3800	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3801	return FALSE;
3802}
3803
3804
3805/**
3806 * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
3807 * @iter: Pointer to incoming dbus message iter
3808 * @error: Location to store error on failure
3809 * @user_data: Function specific data
3810 * Returns: TRUE on success, FALSE on failure
3811 *
3812 * Getter for "WPA" property.
3813 */
3814dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
3815				     void *user_data)
3816{
3817	struct bss_handler_args *args = user_data;
3818	struct wpa_bss *res;
3819	struct wpa_ie_data wpa_data;
3820	const u8 *ie;
3821
3822	res = get_bss_helper(args, error, __func__);
3823	if (!res)
3824		return FALSE;
3825
3826	os_memset(&wpa_data, 0, sizeof(wpa_data));
3827	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
3828	if (ie) {
3829		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3830			dbus_set_error_const(error, DBUS_ERROR_FAILED,
3831					     "failed to parse WPA IE");
3832			return FALSE;
3833		}
3834	}
3835
3836	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3837}
3838
3839
3840/**
3841 * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
3842 * @iter: Pointer to incoming dbus message iter
3843 * @error: Location to store error on failure
3844 * @user_data: Function specific data
3845 * Returns: TRUE on success, FALSE on failure
3846 *
3847 * Getter for "RSN" property.
3848 */
3849dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
3850				     void *user_data)
3851{
3852	struct bss_handler_args *args = user_data;
3853	struct wpa_bss *res;
3854	struct wpa_ie_data wpa_data;
3855	const u8 *ie;
3856
3857	res = get_bss_helper(args, error, __func__);
3858	if (!res)
3859		return FALSE;
3860
3861	os_memset(&wpa_data, 0, sizeof(wpa_data));
3862	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
3863	if (ie) {
3864		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3865			dbus_set_error_const(error, DBUS_ERROR_FAILED,
3866					     "failed to parse RSN IE");
3867			return FALSE;
3868		}
3869	}
3870
3871	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3872}
3873
3874
3875/**
3876 * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
3877 * @iter: Pointer to incoming dbus message iter
3878 * @error: Location to store error on failure
3879 * @user_data: Function specific data
3880 * Returns: TRUE on success, FALSE on failure
3881 *
3882 * Getter for "WPS" property.
3883 */
3884dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
3885				     void *user_data)
3886{
3887	struct bss_handler_args *args = user_data;
3888	struct wpa_bss *res;
3889#ifdef CONFIG_WPS
3890	struct wpabuf *wps_ie;
3891#endif /* CONFIG_WPS */
3892	DBusMessageIter iter_dict, variant_iter;
3893	const char *type = "";
3894
3895	res = get_bss_helper(args, error, __func__);
3896	if (!res)
3897		return FALSE;
3898
3899	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3900					      "a{sv}", &variant_iter))
3901		goto nomem;
3902
3903	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3904		goto nomem;
3905
3906#ifdef CONFIG_WPS
3907	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
3908	if (wps_ie) {
3909		if (wps_is_selected_pbc_registrar(wps_ie))
3910			type = "pbc";
3911		else if (wps_is_selected_pin_registrar(wps_ie))
3912			type = "pin";
3913	}
3914#endif /* CONFIG_WPS */
3915
3916	if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
3917		goto nomem;
3918
3919	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
3920		goto nomem;
3921	if (!dbus_message_iter_close_container(iter, &variant_iter))
3922		goto nomem;
3923
3924	return TRUE;
3925
3926nomem:
3927	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3928	return FALSE;
3929}
3930
3931
3932/**
3933 * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
3934 * @iter: Pointer to incoming dbus message iter
3935 * @error: Location to store error on failure
3936 * @user_data: Function specific data
3937 * Returns: TRUE on success, FALSE on failure
3938 *
3939 * Getter for "IEs" property.
3940 */
3941dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
3942				     void *user_data)
3943{
3944	struct bss_handler_args *args = user_data;
3945	struct wpa_bss *res;
3946
3947	res = get_bss_helper(args, error, __func__);
3948	if (!res)
3949		return FALSE;
3950
3951	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3952						      res + 1, res->ie_len,
3953						      error);
3954}
3955
3956
3957/**
3958 * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
3959 * @iter: Pointer to incoming dbus message iter
3960 * @error: Location to store error on failure
3961 * @user_data: Function specific data
3962 * Returns: TRUE on success, FALSE on failure
3963 *
3964 * Getter for "enabled" property of a configured network.
3965 */
3966dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
3967				     void *user_data)
3968{
3969	struct network_handler_args *net = user_data;
3970	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
3971
3972	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3973						&enabled, error);
3974}
3975
3976
3977/**
3978 * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
3979 * @iter: Pointer to incoming dbus message iter
3980 * @error: Location to store error on failure
3981 * @user_data: Function specific data
3982 * Returns: TRUE on success, FALSE on failure
3983 *
3984 * Setter for "Enabled" property of a configured network.
3985 */
3986dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
3987				     void *user_data)
3988{
3989	struct network_handler_args *net = user_data;
3990	struct wpa_supplicant *wpa_s;
3991	struct wpa_ssid *ssid;
3992	dbus_bool_t enable;
3993
3994	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
3995					      &enable))
3996		return FALSE;
3997
3998	wpa_s = net->wpa_s;
3999	ssid = net->ssid;
4000
4001	if (enable)
4002		wpa_supplicant_enable_network(wpa_s, ssid);
4003	else
4004		wpa_supplicant_disable_network(wpa_s, ssid);
4005
4006	return TRUE;
4007}
4008
4009
4010/**
4011 * wpas_dbus_getter_network_properties - Get options for a configured network
4012 * @iter: Pointer to incoming dbus message iter
4013 * @error: Location to store error on failure
4014 * @user_data: Function specific data
4015 * Returns: TRUE on success, FALSE on failure
4016 *
4017 * Getter for "Properties" property of a configured network.
4018 */
4019dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
4020						DBusError *error,
4021						void *user_data)
4022{
4023	struct network_handler_args *net = user_data;
4024	DBusMessageIter	variant_iter, dict_iter;
4025	char **iterator;
4026	char **props = wpa_config_get_all(net->ssid, 1);
4027	dbus_bool_t success = FALSE;
4028
4029	if (!props) {
4030		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4031		return FALSE;
4032	}
4033
4034	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
4035					      &variant_iter) ||
4036	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
4037		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4038		goto out;
4039	}
4040
4041	iterator = props;
4042	while (*iterator) {
4043		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
4044						 *(iterator + 1))) {
4045			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4046					     "no memory");
4047			goto out;
4048		}
4049		iterator += 2;
4050	}
4051
4052
4053	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
4054	    !dbus_message_iter_close_container(iter, &variant_iter)) {
4055		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4056		goto out;
4057	}
4058
4059	success = TRUE;
4060
4061out:
4062	iterator = props;
4063	while (*iterator) {
4064		os_free(*iterator);
4065		iterator++;
4066	}
4067	os_free(props);
4068	return success;
4069}
4070
4071
4072/**
4073 * wpas_dbus_setter_network_properties - Set options for a configured network
4074 * @iter: Pointer to incoming dbus message iter
4075 * @error: Location to store error on failure
4076 * @user_data: Function specific data
4077 * Returns: TRUE on success, FALSE on failure
4078 *
4079 * Setter for "Properties" property of a configured network.
4080 */
4081dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
4082						DBusError *error,
4083						void *user_data)
4084{
4085	struct network_handler_args *net = user_data;
4086	struct wpa_ssid *ssid = net->ssid;
4087	DBusMessageIter	variant_iter;
4088
4089	dbus_message_iter_recurse(iter, &variant_iter);
4090	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
4091}
4092
4093
4094#ifdef CONFIG_AP
4095
4096DBusMessage * wpas_dbus_handler_subscribe_preq(
4097	DBusMessage *message, struct wpa_supplicant *wpa_s)
4098{
4099	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4100	char *name;
4101
4102	if (wpa_s->preq_notify_peer != NULL) {
4103		if (os_strcmp(dbus_message_get_sender(message),
4104			      wpa_s->preq_notify_peer) == 0)
4105			return NULL;
4106
4107		return dbus_message_new_error(message,
4108			WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
4109			"Another application is already subscribed");
4110	}
4111
4112	name = os_strdup(dbus_message_get_sender(message));
4113	if (!name)
4114		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
4115					      "out of memory");
4116
4117	wpa_s->preq_notify_peer = name;
4118
4119	/* Subscribe to clean up if application closes socket */
4120	wpas_dbus_subscribe_noc(priv);
4121
4122	/*
4123	 * Double-check it's still alive to make sure that we didn't
4124	 * miss the NameOwnerChanged signal, e.g. while strdup'ing.
4125	 */
4126	if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
4127		/*
4128		 * Application no longer exists, clean up.
4129		 * The return value is irrelevant now.
4130		 *
4131		 * Need to check if the NameOwnerChanged handling
4132		 * already cleaned up because we have processed
4133		 * DBus messages while checking if the name still
4134		 * has an owner.
4135		 */
4136		if (!wpa_s->preq_notify_peer)
4137			return NULL;
4138		os_free(wpa_s->preq_notify_peer);
4139		wpa_s->preq_notify_peer = NULL;
4140		wpas_dbus_unsubscribe_noc(priv);
4141	}
4142
4143	return NULL;
4144}
4145
4146
4147DBusMessage * wpas_dbus_handler_unsubscribe_preq(
4148	DBusMessage *message, struct wpa_supplicant *wpa_s)
4149{
4150	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4151
4152	if (!wpa_s->preq_notify_peer)
4153		return dbus_message_new_error(message,
4154			WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
4155			"Not subscribed");
4156
4157	if (os_strcmp(wpa_s->preq_notify_peer,
4158		      dbus_message_get_sender(message)))
4159		return dbus_message_new_error(message,
4160			WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
4161			"Can't unsubscribe others");
4162
4163	os_free(wpa_s->preq_notify_peer);
4164	wpa_s->preq_notify_peer = NULL;
4165	wpas_dbus_unsubscribe_noc(priv);
4166	return NULL;
4167}
4168
4169
4170void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
4171			   const u8 *addr, const u8 *dst, const u8 *bssid,
4172			   const u8 *ie, size_t ie_len, u32 ssi_signal)
4173{
4174	DBusMessage *msg;
4175	DBusMessageIter iter, dict_iter;
4176	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4177
4178	/* Do nothing if the control interface is not turned on */
4179	if (priv == NULL)
4180		return;
4181
4182	if (wpa_s->preq_notify_peer == NULL)
4183		return;
4184
4185	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
4186				      WPAS_DBUS_NEW_IFACE_INTERFACE,
4187				      "ProbeRequest");
4188	if (msg == NULL)
4189		return;
4190
4191	dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
4192
4193	dbus_message_iter_init_append(msg, &iter);
4194
4195	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
4196		goto fail;
4197	if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
4198						     (const char *) addr,
4199						     ETH_ALEN))
4200		goto fail;
4201	if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
4202						    (const char *) dst,
4203						    ETH_ALEN))
4204		goto fail;
4205	if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
4206						      (const char *) bssid,
4207						      ETH_ALEN))
4208		goto fail;
4209	if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
4210							     (const char *) ie,
4211							     ie_len))
4212		goto fail;
4213	if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
4214						      ssi_signal))
4215		goto fail;
4216	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
4217		goto fail;
4218
4219	dbus_connection_send(priv->con, msg, NULL);
4220	goto out;
4221fail:
4222	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
4223out:
4224	dbus_message_unref(msg);
4225}
4226
4227#endif /* CONFIG_AP */
4228