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