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