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