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