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