dbus_new_handlers.c revision fb79edc9df1f20461e90e478363d207348213d35
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_remove_network - Remove a configured network
1491 * @message: Pointer to incoming dbus message
1492 * @wpa_s: wpa_supplicant structure for a network interface
1493 * Returns: NULL on success or dbus error on failure
1494 *
1495 * Handler function for "RemoveNetwork" method call of a network interface.
1496 */
1497DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
1498					       struct wpa_supplicant *wpa_s)
1499{
1500	DBusMessage *reply = NULL;
1501	const char *op;
1502	char *iface = NULL, *net_id = NULL;
1503	int id;
1504	struct wpa_ssid *ssid;
1505	int was_disabled;
1506
1507	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1508			      DBUS_TYPE_INVALID);
1509
1510	/* Extract the network ID and ensure the network */
1511	/* is actually a child of this interface */
1512	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
1513	if (iface == NULL || net_id == NULL ||
1514	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1515		reply = wpas_dbus_error_invalid_args(message, op);
1516		goto out;
1517	}
1518
1519	errno = 0;
1520	id = strtoul(net_id, NULL, 10);
1521	if (errno != 0) {
1522		reply = wpas_dbus_error_invalid_args(message, op);
1523		goto out;
1524	}
1525
1526	ssid = wpa_config_get_network(wpa_s->conf, id);
1527	if (ssid == NULL) {
1528		reply = wpas_dbus_error_network_unknown(message);
1529		goto out;
1530	}
1531
1532	was_disabled = ssid->disabled;
1533
1534	wpas_notify_network_removed(wpa_s, ssid);
1535
1536	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1537		wpa_printf(MSG_ERROR,
1538			   "wpas_dbus_handler_remove_network[dbus]: "
1539			   "error occurred when removing network %d", id);
1540		reply = wpas_dbus_error_unknown_error(
1541			message, "error removing the specified network on "
1542			"this interface.");
1543		goto out;
1544	}
1545
1546	if (ssid == wpa_s->current_ssid)
1547		wpa_supplicant_deauthenticate(wpa_s,
1548					      WLAN_REASON_DEAUTH_LEAVING);
1549	else if (!was_disabled && wpa_s->sched_scanning) {
1550		wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
1551			   "network from filters");
1552		wpa_supplicant_cancel_sched_scan(wpa_s);
1553		wpa_supplicant_req_scan(wpa_s, 0, 0);
1554	}
1555
1556
1557out:
1558	os_free(iface);
1559	os_free(net_id);
1560	return reply;
1561}
1562
1563
1564static void remove_network(void *arg, struct wpa_ssid *ssid)
1565{
1566	struct wpa_supplicant *wpa_s = arg;
1567
1568	wpas_notify_network_removed(wpa_s, ssid);
1569
1570	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1571		wpa_printf(MSG_ERROR,
1572			   "wpas_dbus_handler_remove_all_networks[dbus]: "
1573			   "error occurred when removing network %d",
1574			   ssid->id);
1575		return;
1576	}
1577
1578	if (ssid == wpa_s->current_ssid)
1579		wpa_supplicant_deauthenticate(wpa_s,
1580					      WLAN_REASON_DEAUTH_LEAVING);
1581}
1582
1583
1584/**
1585 * wpas_dbus_handler_remove_all_networks - Remove all configured networks
1586 * @message: Pointer to incoming dbus message
1587 * @wpa_s: wpa_supplicant structure for a network interface
1588 * Returns: NULL on success or dbus error on failure
1589 *
1590 * Handler function for "RemoveAllNetworks" method call of a network interface.
1591 */
1592DBusMessage * wpas_dbus_handler_remove_all_networks(
1593	DBusMessage *message, struct wpa_supplicant *wpa_s)
1594{
1595	if (wpa_s->sched_scanning)
1596		wpa_supplicant_cancel_sched_scan(wpa_s);
1597
1598	/* NB: could check for failure and return an error */
1599	wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
1600	return NULL;
1601}
1602
1603
1604/**
1605 * wpas_dbus_handler_select_network - Attempt association with a network
1606 * @message: Pointer to incoming dbus message
1607 * @wpa_s: wpa_supplicant structure for a network interface
1608 * Returns: NULL on success or dbus error on failure
1609 *
1610 * Handler function for "SelectNetwork" method call of network interface.
1611 */
1612DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
1613					       struct wpa_supplicant *wpa_s)
1614{
1615	DBusMessage *reply = NULL;
1616	const char *op;
1617	char *iface = NULL, *net_id = NULL;
1618	int id;
1619	struct wpa_ssid *ssid;
1620
1621	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1622			      DBUS_TYPE_INVALID);
1623
1624	/* Extract the network ID and ensure the network */
1625	/* is actually a child of this interface */
1626	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
1627	if (iface == NULL || net_id == NULL ||
1628	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1629		reply = wpas_dbus_error_invalid_args(message, op);
1630		goto out;
1631	}
1632
1633	errno = 0;
1634	id = strtoul(net_id, NULL, 10);
1635	if (errno != 0) {
1636		reply = wpas_dbus_error_invalid_args(message, op);
1637		goto out;
1638	}
1639
1640	ssid = wpa_config_get_network(wpa_s->conf, id);
1641	if (ssid == NULL) {
1642		reply = wpas_dbus_error_network_unknown(message);
1643		goto out;
1644	}
1645
1646	/* Finally, associate with the network */
1647	wpa_supplicant_select_network(wpa_s, ssid);
1648
1649out:
1650	os_free(iface);
1651	os_free(net_id);
1652	return reply;
1653}
1654
1655
1656/**
1657 * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
1658 * @message: Pointer to incoming dbus message
1659 * @wpa_s: wpa_supplicant structure for a network interface
1660 * Returns: NULL on success or dbus error on failure
1661 *
1662 * Handler function for "NetworkReply" method call of network interface.
1663 */
1664DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
1665					      struct wpa_supplicant *wpa_s)
1666{
1667#ifdef IEEE8021X_EAPOL
1668	DBusMessage *reply = NULL;
1669	const char *op, *field, *value;
1670	char *iface = NULL, *net_id = NULL;
1671	int id;
1672	struct wpa_ssid *ssid;
1673
1674	if (!dbus_message_get_args(message, NULL,
1675	                           DBUS_TYPE_OBJECT_PATH, &op,
1676	                           DBUS_TYPE_STRING, &field,
1677	                           DBUS_TYPE_STRING, &value,
1678			           DBUS_TYPE_INVALID))
1679		return wpas_dbus_error_invalid_args(message, NULL);
1680
1681	/* Extract the network ID and ensure the network */
1682	/* is actually a child of this interface */
1683	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
1684	if (iface == NULL || net_id == NULL ||
1685	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1686		reply = wpas_dbus_error_invalid_args(message, op);
1687		goto out;
1688	}
1689
1690	errno = 0;
1691	id = strtoul(net_id, NULL, 10);
1692	if (errno != 0) {
1693		reply = wpas_dbus_error_invalid_args(message, net_id);
1694		goto out;
1695	}
1696
1697	ssid = wpa_config_get_network(wpa_s->conf, id);
1698	if (ssid == NULL) {
1699		reply = wpas_dbus_error_network_unknown(message);
1700		goto out;
1701	}
1702
1703	if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
1704						      field, value) < 0)
1705		reply = wpas_dbus_error_invalid_args(message, field);
1706	else {
1707		/* Tell EAP to retry immediately */
1708		eapol_sm_notify_ctrl_response(wpa_s->eapol);
1709	}
1710
1711out:
1712	os_free(iface);
1713	os_free(net_id);
1714	return reply;
1715#else /* IEEE8021X_EAPOL */
1716	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1717	return wpas_dbus_error_unknown_error(message, "802.1X not included");
1718#endif /* IEEE8021X_EAPOL */
1719}
1720
1721
1722#ifndef CONFIG_NO_CONFIG_BLOBS
1723
1724/**
1725 * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
1726 * @message: Pointer to incoming dbus message
1727 * @wpa_s: %wpa_supplicant data structure
1728 * Returns: A dbus message containing an error on failure or NULL on success
1729 *
1730 * Asks wpa_supplicant to internally store a binary blobs.
1731 */
1732DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
1733					 struct wpa_supplicant *wpa_s)
1734{
1735	DBusMessage *reply = NULL;
1736	DBusMessageIter	iter, array_iter;
1737
1738	char *blob_name;
1739	u8 *blob_data;
1740	int blob_len;
1741	struct wpa_config_blob *blob = NULL;
1742
1743	dbus_message_iter_init(message, &iter);
1744	dbus_message_iter_get_basic(&iter, &blob_name);
1745
1746	if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
1747		return dbus_message_new_error(message,
1748					      WPAS_DBUS_ERROR_BLOB_EXISTS,
1749					      NULL);
1750	}
1751
1752	dbus_message_iter_next(&iter);
1753	dbus_message_iter_recurse(&iter, &array_iter);
1754
1755	dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
1756
1757	blob = os_zalloc(sizeof(*blob));
1758	if (!blob) {
1759		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1760					       NULL);
1761		goto err;
1762	}
1763
1764	blob->data = os_malloc(blob_len);
1765	if (!blob->data) {
1766		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1767					       NULL);
1768		goto err;
1769	}
1770	os_memcpy(blob->data, blob_data, blob_len);
1771
1772	blob->len = blob_len;
1773	blob->name = os_strdup(blob_name);
1774	if (!blob->name) {
1775		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1776					       NULL);
1777		goto err;
1778	}
1779
1780	wpa_config_set_blob(wpa_s->conf, blob);
1781	wpas_notify_blob_added(wpa_s, blob->name);
1782
1783	return reply;
1784
1785err:
1786	if (blob) {
1787		os_free(blob->name);
1788		os_free(blob->data);
1789		os_free(blob);
1790	}
1791	return reply;
1792}
1793
1794
1795/**
1796 * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
1797 * @message: Pointer to incoming dbus message
1798 * @wpa_s: %wpa_supplicant data structure
1799 * Returns: A dbus message containing array of bytes (blob)
1800 *
1801 * Gets one wpa_supplicant's binary blobs.
1802 */
1803DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
1804					 struct wpa_supplicant *wpa_s)
1805{
1806	DBusMessage *reply = NULL;
1807	DBusMessageIter	iter, array_iter;
1808
1809	char *blob_name;
1810	const struct wpa_config_blob *blob;
1811
1812	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1813			      DBUS_TYPE_INVALID);
1814
1815	blob = wpa_config_get_blob(wpa_s->conf, blob_name);
1816	if (!blob) {
1817		return dbus_message_new_error(message,
1818					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1819					      "Blob id not set");
1820	}
1821
1822	reply = dbus_message_new_method_return(message);
1823	if (!reply) {
1824		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1825					       NULL);
1826		goto out;
1827	}
1828
1829	dbus_message_iter_init_append(reply, &iter);
1830
1831	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1832					      DBUS_TYPE_BYTE_AS_STRING,
1833					      &array_iter)) {
1834		dbus_message_unref(reply);
1835		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1836					       NULL);
1837		goto out;
1838	}
1839
1840	if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
1841						  &(blob->data), blob->len)) {
1842		dbus_message_unref(reply);
1843		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1844					       NULL);
1845		goto out;
1846	}
1847
1848	if (!dbus_message_iter_close_container(&iter, &array_iter)) {
1849		dbus_message_unref(reply);
1850		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1851					       NULL);
1852		goto out;
1853	}
1854
1855out:
1856	return reply;
1857}
1858
1859
1860/**
1861 * wpas_remove_handler_remove_blob - Remove named binary blob
1862 * @message: Pointer to incoming dbus message
1863 * @wpa_s: %wpa_supplicant data structure
1864 * Returns: NULL on success or dbus error
1865 *
1866 * Asks wpa_supplicant to internally remove a binary blobs.
1867 */
1868DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
1869					    struct wpa_supplicant *wpa_s)
1870{
1871	DBusMessage *reply = NULL;
1872	char *blob_name;
1873
1874	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1875			      DBUS_TYPE_INVALID);
1876
1877	if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
1878		return dbus_message_new_error(message,
1879					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1880					      "Blob id not set");
1881	}
1882	wpas_notify_blob_removed(wpa_s, blob_name);
1883
1884	return reply;
1885
1886}
1887
1888#endif /* CONFIG_NO_CONFIG_BLOBS */
1889
1890
1891/*
1892 * wpas_dbus_handler_flush_bss - Flush the BSS cache
1893 * @message: Pointer to incoming dbus message
1894 * @wpa_s: wpa_supplicant structure for a network interface
1895 * Returns: NULL
1896 *
1897 * Handler function for "FlushBSS" method call of network interface.
1898 */
1899DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
1900					  struct wpa_supplicant *wpa_s)
1901{
1902	dbus_uint32_t age;
1903
1904	dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
1905			      DBUS_TYPE_INVALID);
1906
1907	if (age == 0)
1908		wpa_bss_flush(wpa_s);
1909	else
1910		wpa_bss_flush_by_age(wpa_s, age);
1911
1912	return NULL;
1913}
1914
1915
1916#ifdef CONFIG_AUTOSCAN
1917/**
1918 * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
1919 * @message: Pointer to incoming dbus message
1920 * @wpa_s: wpa_supplicant structure for a network interface
1921 * Returns: NULL
1922 *
1923 * Handler function for "AutoScan" method call of network interface.
1924 */
1925DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
1926					 struct wpa_supplicant *wpa_s)
1927{
1928	DBusMessage *reply = NULL;
1929	enum wpa_states state = wpa_s->wpa_state;
1930	char *arg;
1931
1932	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
1933			      DBUS_TYPE_INVALID);
1934
1935	if (arg != NULL && os_strlen(arg) > 0) {
1936		char *tmp;
1937		tmp = os_strdup(arg);
1938		if (tmp == NULL) {
1939			reply = dbus_message_new_error(message,
1940						       DBUS_ERROR_NO_MEMORY,
1941						       NULL);
1942		} else {
1943			os_free(wpa_s->conf->autoscan);
1944			wpa_s->conf->autoscan = tmp;
1945			if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
1946				autoscan_init(wpa_s, 1);
1947			else if (state == WPA_SCANNING)
1948				wpa_supplicant_reinit_autoscan(wpa_s);
1949		}
1950	} else if (arg != NULL && os_strlen(arg) == 0) {
1951		os_free(wpa_s->conf->autoscan);
1952		wpa_s->conf->autoscan = NULL;
1953		autoscan_deinit(wpa_s);
1954	} else
1955		reply = dbus_message_new_error(message,
1956					       DBUS_ERROR_INVALID_ARGS,
1957					       NULL);
1958
1959	return reply;
1960}
1961#endif /* CONFIG_AUTOSCAN */
1962
1963
1964/*
1965 * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
1966 * @message: Pointer to incoming dbus message
1967 * @wpa_s: wpa_supplicant structure for a network interface
1968 * Returns: NULL
1969 *
1970 * Handler function for "EAPLogoff" method call of network interface.
1971 */
1972DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
1973					   struct wpa_supplicant *wpa_s)
1974{
1975	eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
1976	return NULL;
1977}
1978
1979
1980/*
1981 * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
1982 * @message: Pointer to incoming dbus message
1983 * @wpa_s: wpa_supplicant structure for a network interface
1984 * Returns: NULL
1985 *
1986 * Handler function for "EAPLogin" method call of network interface.
1987 */
1988DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
1989					  struct wpa_supplicant *wpa_s)
1990{
1991	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
1992	return NULL;
1993}
1994
1995
1996#ifdef CONFIG_TDLS
1997
1998static DBusMessage * get_peer_hwaddr_helper(DBusMessage *message,
1999					    const char *func_name,
2000					    u8 *peer_address)
2001{
2002	const char *peer_string;
2003
2004	if (!dbus_message_get_args(message, NULL,
2005				   DBUS_TYPE_STRING, &peer_string,
2006				   DBUS_TYPE_INVALID))
2007		return wpas_dbus_error_invalid_args(message, NULL);
2008
2009	if (hwaddr_aton(peer_string, peer_address)) {
2010		wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
2011			   func_name, peer_string);
2012		return wpas_dbus_error_invalid_args(
2013			message, "Invalid hardware address format");
2014	}
2015
2016	return NULL;
2017}
2018
2019
2020/*
2021 * wpas_dbus_handler_tdls_discover - Discover TDLS peer
2022 * @message: Pointer to incoming dbus message
2023 * @wpa_s: wpa_supplicant structure for a network interface
2024 * Returns: NULL indicating success or DBus error message on failure
2025 *
2026 * Handler function for "TDLSDiscover" method call of network interface.
2027 */
2028DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
2029					      struct wpa_supplicant *wpa_s)
2030{
2031	u8 peer[ETH_ALEN];
2032	DBusMessage *error_reply;
2033	int ret;
2034
2035	error_reply = get_peer_hwaddr_helper(message, __func__, peer);
2036	if (error_reply)
2037		return error_reply;
2038
2039	wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
2040
2041	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2042		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
2043	else
2044		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
2045
2046	if (ret) {
2047		return wpas_dbus_error_unknown_error(
2048			message, "error performing TDLS discovery");
2049	}
2050
2051	return NULL;
2052}
2053
2054
2055/*
2056 * wpas_dbus_handler_tdls_setup - Setup TDLS session
2057 * @message: Pointer to incoming dbus message
2058 * @wpa_s: wpa_supplicant structure for a network interface
2059 * Returns: NULL indicating success or DBus error message on failure
2060 *
2061 * Handler function for "TDLSSetup" method call of network interface.
2062 */
2063DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
2064					   struct wpa_supplicant *wpa_s)
2065{
2066	u8 peer[ETH_ALEN];
2067	DBusMessage *error_reply;
2068	int ret;
2069
2070	error_reply = get_peer_hwaddr_helper(message, __func__, peer);
2071	if (error_reply)
2072		return error_reply;
2073
2074	wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
2075
2076	wpa_tdls_remove(wpa_s->wpa, peer);
2077	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2078		ret = wpa_tdls_start(wpa_s->wpa, peer);
2079	else
2080		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2081
2082	if (ret) {
2083		return wpas_dbus_error_unknown_error(
2084			message, "error performing TDLS setup");
2085	}
2086
2087	return NULL;
2088}
2089
2090
2091/*
2092 * wpas_dbus_handler_tdls_status - Return TDLS session status
2093 * @message: Pointer to incoming dbus message
2094 * @wpa_s: wpa_supplicant structure for a network interface
2095 * Returns: A string representing the state of the link to this TDLS peer
2096 *
2097 * Handler function for "TDLSStatus" method call of network interface.
2098 */
2099DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
2100					    struct wpa_supplicant *wpa_s)
2101{
2102	u8 peer[ETH_ALEN];
2103	DBusMessage *reply;
2104	const char *tdls_status;
2105
2106	reply = get_peer_hwaddr_helper(message, __func__, peer);
2107	if (reply)
2108		return reply;
2109
2110	wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
2111
2112	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
2113
2114	reply = dbus_message_new_method_return(message);
2115	dbus_message_append_args(reply, DBUS_TYPE_STRING,
2116				 &tdls_status, DBUS_TYPE_INVALID);
2117	return reply;
2118}
2119
2120
2121/*
2122 * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
2123 * @message: Pointer to incoming dbus message
2124 * @wpa_s: wpa_supplicant structure for a network interface
2125 * Returns: NULL indicating success or DBus error message on failure
2126 *
2127 * Handler function for "TDLSTeardown" method call of network interface.
2128 */
2129DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
2130					      struct wpa_supplicant *wpa_s)
2131{
2132	u8 peer[ETH_ALEN];
2133	DBusMessage *error_reply;
2134	int ret;
2135
2136	error_reply = get_peer_hwaddr_helper(message, __func__, peer);
2137	if (error_reply)
2138		return error_reply;
2139
2140	wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
2141
2142	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2143		ret = wpa_tdls_teardown_link(
2144			wpa_s->wpa, peer,
2145			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
2146	else
2147		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
2148
2149	if (ret) {
2150		return wpas_dbus_error_unknown_error(
2151			message, "error performing TDLS teardown");
2152	}
2153
2154	return NULL;
2155}
2156
2157#endif /* CONFIG_TDLS */
2158
2159
2160/**
2161 * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
2162 * @message: Pointer to incoming dbus message
2163 * @wpa_s: %wpa_supplicant data structure
2164 * Returns: A dbus message containing an error on failure or NULL on success
2165 *
2166 * Sets the PKCS #11 engine and module path.
2167 */
2168DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
2169	DBusMessage *message, struct wpa_supplicant *wpa_s)
2170{
2171	DBusMessageIter iter;
2172	char *value = NULL;
2173	char *pkcs11_engine_path = NULL;
2174	char *pkcs11_module_path = NULL;
2175
2176	dbus_message_iter_init(message, &iter);
2177	dbus_message_iter_get_basic(&iter, &value);
2178	if (value == NULL) {
2179		return dbus_message_new_error(
2180			message, DBUS_ERROR_INVALID_ARGS,
2181			"Invalid pkcs11_engine_path argument");
2182	}
2183	/* Empty path defaults to NULL */
2184	if (os_strlen(value))
2185		pkcs11_engine_path = value;
2186
2187	dbus_message_iter_next(&iter);
2188	dbus_message_iter_get_basic(&iter, &value);
2189	if (value == NULL) {
2190		os_free(pkcs11_engine_path);
2191		return dbus_message_new_error(
2192			message, DBUS_ERROR_INVALID_ARGS,
2193			"Invalid pkcs11_module_path argument");
2194	}
2195	/* Empty path defaults to NULL */
2196	if (os_strlen(value))
2197		pkcs11_module_path = value;
2198
2199	if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
2200						   pkcs11_module_path))
2201		return dbus_message_new_error(
2202			message, DBUS_ERROR_FAILED,
2203			"Reinit of the EAPOL state machine with the new PKCS "
2204			"#11 engine and module path failed.");
2205
2206	wpa_dbus_mark_property_changed(
2207		wpa_s->global->dbus, wpa_s->dbus_new_path,
2208		WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
2209	wpa_dbus_mark_property_changed(
2210		wpa_s->global->dbus, wpa_s->dbus_new_path,
2211		WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
2212
2213	return NULL;
2214}
2215
2216
2217/**
2218 * wpas_dbus_getter_capabilities - Return interface capabilities
2219 * @iter: Pointer to incoming dbus message iter
2220 * @error: Location to store error on failure
2221 * @user_data: Function specific data
2222 * Returns: TRUE on success, FALSE on failure
2223 *
2224 * Getter for "Capabilities" property of an interface.
2225 */
2226dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
2227					  DBusError *error, void *user_data)
2228{
2229	struct wpa_supplicant *wpa_s = user_data;
2230	struct wpa_driver_capa capa;
2231	int res;
2232	DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
2233		variant_iter;
2234	const char *scans[] = { "active", "passive", "ssid" };
2235
2236	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
2237					      "a{sv}", &variant_iter))
2238		goto nomem;
2239
2240	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
2241		goto nomem;
2242
2243	res = wpa_drv_get_capa(wpa_s, &capa);
2244
2245	/***** pairwise cipher */
2246	if (res < 0) {
2247		const char *args[] = {"ccmp", "tkip", "none"};
2248		if (!wpa_dbus_dict_append_string_array(
2249			    &iter_dict, "Pairwise", args,
2250			    ARRAY_SIZE(args)))
2251			goto nomem;
2252	} else {
2253		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
2254						      &iter_dict_entry,
2255						      &iter_dict_val,
2256						      &iter_array))
2257			goto nomem;
2258
2259		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
2260			if (!wpa_dbus_dict_string_array_add_element(
2261				    &iter_array, "ccmp-256"))
2262				goto nomem;
2263		}
2264
2265		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
2266			if (!wpa_dbus_dict_string_array_add_element(
2267				    &iter_array, "gcmp-256"))
2268				goto nomem;
2269		}
2270
2271		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2272			if (!wpa_dbus_dict_string_array_add_element(
2273				    &iter_array, "ccmp"))
2274				goto nomem;
2275		}
2276
2277		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2278			if (!wpa_dbus_dict_string_array_add_element(
2279				    &iter_array, "gcmp"))
2280				goto nomem;
2281		}
2282
2283		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2284			if (!wpa_dbus_dict_string_array_add_element(
2285				    &iter_array, "tkip"))
2286				goto nomem;
2287		}
2288
2289		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2290			if (!wpa_dbus_dict_string_array_add_element(
2291				    &iter_array, "none"))
2292				goto nomem;
2293		}
2294
2295		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2296						    &iter_dict_entry,
2297						    &iter_dict_val,
2298						    &iter_array))
2299			goto nomem;
2300	}
2301
2302	/***** group cipher */
2303	if (res < 0) {
2304		const char *args[] = {
2305			"ccmp", "tkip", "wep104", "wep40"
2306		};
2307		if (!wpa_dbus_dict_append_string_array(
2308			    &iter_dict, "Group", args,
2309			    ARRAY_SIZE(args)))
2310			goto nomem;
2311	} else {
2312		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
2313						      &iter_dict_entry,
2314						      &iter_dict_val,
2315						      &iter_array))
2316			goto nomem;
2317
2318		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
2319			if (!wpa_dbus_dict_string_array_add_element(
2320				    &iter_array, "ccmp-256"))
2321				goto nomem;
2322		}
2323
2324		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
2325			if (!wpa_dbus_dict_string_array_add_element(
2326				    &iter_array, "gcmp-256"))
2327				goto nomem;
2328		}
2329
2330		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2331			if (!wpa_dbus_dict_string_array_add_element(
2332				    &iter_array, "ccmp"))
2333				goto nomem;
2334		}
2335
2336		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2337			if (!wpa_dbus_dict_string_array_add_element(
2338				    &iter_array, "gcmp"))
2339				goto nomem;
2340		}
2341
2342		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2343			if (!wpa_dbus_dict_string_array_add_element(
2344				    &iter_array, "tkip"))
2345				goto nomem;
2346		}
2347
2348		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
2349			if (!wpa_dbus_dict_string_array_add_element(
2350				    &iter_array, "wep104"))
2351				goto nomem;
2352		}
2353
2354		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
2355			if (!wpa_dbus_dict_string_array_add_element(
2356				    &iter_array, "wep40"))
2357				goto nomem;
2358		}
2359
2360		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2361						    &iter_dict_entry,
2362						    &iter_dict_val,
2363						    &iter_array))
2364			goto nomem;
2365	}
2366
2367	/***** key management */
2368	if (res < 0) {
2369		const char *args[] = {
2370			"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
2371#ifdef CONFIG_WPS
2372			"wps",
2373#endif /* CONFIG_WPS */
2374			"none"
2375		};
2376		if (!wpa_dbus_dict_append_string_array(
2377			    &iter_dict, "KeyMgmt", args,
2378			    ARRAY_SIZE(args)))
2379			goto nomem;
2380	} else {
2381		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
2382						      &iter_dict_entry,
2383						      &iter_dict_val,
2384						      &iter_array))
2385			goto nomem;
2386
2387		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2388							    "none"))
2389			goto nomem;
2390
2391		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2392							    "ieee8021x"))
2393			goto nomem;
2394
2395		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2396				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2397			if (!wpa_dbus_dict_string_array_add_element(
2398				    &iter_array, "wpa-eap"))
2399				goto nomem;
2400
2401			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
2402				if (!wpa_dbus_dict_string_array_add_element(
2403					    &iter_array, "wpa-ft-eap"))
2404					goto nomem;
2405
2406/* TODO: Ensure that driver actually supports sha256 encryption. */
2407#ifdef CONFIG_IEEE80211W
2408			if (!wpa_dbus_dict_string_array_add_element(
2409				    &iter_array, "wpa-eap-sha256"))
2410				goto nomem;
2411#endif /* CONFIG_IEEE80211W */
2412		}
2413
2414		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2415				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2416			if (!wpa_dbus_dict_string_array_add_element(
2417				    &iter_array, "wpa-psk"))
2418				goto nomem;
2419
2420			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
2421				if (!wpa_dbus_dict_string_array_add_element(
2422					    &iter_array, "wpa-ft-psk"))
2423					goto nomem;
2424
2425/* TODO: Ensure that driver actually supports sha256 encryption. */
2426#ifdef CONFIG_IEEE80211W
2427			if (!wpa_dbus_dict_string_array_add_element(
2428				    &iter_array, "wpa-psk-sha256"))
2429				goto nomem;
2430#endif /* CONFIG_IEEE80211W */
2431		}
2432
2433		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2434			if (!wpa_dbus_dict_string_array_add_element(
2435				    &iter_array, "wpa-none"))
2436				goto nomem;
2437		}
2438
2439
2440#ifdef CONFIG_WPS
2441		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2442							    "wps"))
2443			goto nomem;
2444#endif /* CONFIG_WPS */
2445
2446		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2447						    &iter_dict_entry,
2448						    &iter_dict_val,
2449						    &iter_array))
2450			goto nomem;
2451	}
2452
2453	/***** WPA protocol */
2454	if (res < 0) {
2455		const char *args[] = { "rsn", "wpa" };
2456		if (!wpa_dbus_dict_append_string_array(
2457			    &iter_dict, "Protocol", args,
2458			    ARRAY_SIZE(args)))
2459			goto nomem;
2460	} else {
2461		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
2462						      &iter_dict_entry,
2463						      &iter_dict_val,
2464						      &iter_array))
2465			goto nomem;
2466
2467		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2468				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2469			if (!wpa_dbus_dict_string_array_add_element(
2470				    &iter_array, "rsn"))
2471				goto nomem;
2472		}
2473
2474		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2475				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
2476			if (!wpa_dbus_dict_string_array_add_element(
2477				    &iter_array, "wpa"))
2478				goto nomem;
2479		}
2480
2481		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2482						    &iter_dict_entry,
2483						    &iter_dict_val,
2484						    &iter_array))
2485			goto nomem;
2486	}
2487
2488	/***** auth alg */
2489	if (res < 0) {
2490		const char *args[] = { "open", "shared", "leap" };
2491		if (!wpa_dbus_dict_append_string_array(
2492			    &iter_dict, "AuthAlg", args,
2493			    ARRAY_SIZE(args)))
2494			goto nomem;
2495	} else {
2496		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
2497						      &iter_dict_entry,
2498						      &iter_dict_val,
2499						      &iter_array))
2500			goto nomem;
2501
2502		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
2503			if (!wpa_dbus_dict_string_array_add_element(
2504				    &iter_array, "open"))
2505				goto nomem;
2506		}
2507
2508		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
2509			if (!wpa_dbus_dict_string_array_add_element(
2510				    &iter_array, "shared"))
2511				goto nomem;
2512		}
2513
2514		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
2515			if (!wpa_dbus_dict_string_array_add_element(
2516				    &iter_array, "leap"))
2517				goto nomem;
2518		}
2519
2520		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2521						    &iter_dict_entry,
2522						    &iter_dict_val,
2523						    &iter_array))
2524			goto nomem;
2525	}
2526
2527	/***** Scan */
2528	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
2529					       ARRAY_SIZE(scans)))
2530		goto nomem;
2531
2532	/***** Modes */
2533	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
2534					      &iter_dict_entry,
2535					      &iter_dict_val,
2536					      &iter_array))
2537		goto nomem;
2538
2539	if (!wpa_dbus_dict_string_array_add_element(
2540			    &iter_array, "infrastructure"))
2541		goto nomem;
2542
2543	if (!wpa_dbus_dict_string_array_add_element(
2544			    &iter_array, "ad-hoc"))
2545		goto nomem;
2546
2547	if (res >= 0) {
2548		if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
2549			if (!wpa_dbus_dict_string_array_add_element(
2550				    &iter_array, "ap"))
2551				goto nomem;
2552		}
2553
2554		if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
2555			if (!wpa_dbus_dict_string_array_add_element(
2556				    &iter_array, "p2p"))
2557				goto nomem;
2558		}
2559	}
2560
2561	if (!wpa_dbus_dict_end_string_array(&iter_dict,
2562					    &iter_dict_entry,
2563					    &iter_dict_val,
2564					    &iter_array))
2565		goto nomem;
2566	/***** Modes end */
2567
2568	if (res >= 0) {
2569		dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
2570
2571		if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
2572						max_scan_ssid))
2573			goto nomem;
2574	}
2575
2576	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
2577		goto nomem;
2578	if (!dbus_message_iter_close_container(iter, &variant_iter))
2579		goto nomem;
2580
2581	return TRUE;
2582
2583nomem:
2584	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2585	return FALSE;
2586}
2587
2588
2589/**
2590 * wpas_dbus_getter_state - Get interface state
2591 * @iter: Pointer to incoming dbus message iter
2592 * @error: Location to store error on failure
2593 * @user_data: Function specific data
2594 * Returns: TRUE on success, FALSE on failure
2595 *
2596 * Getter for "State" property.
2597 */
2598dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
2599				   void *user_data)
2600{
2601	struct wpa_supplicant *wpa_s = user_data;
2602	const char *str_state;
2603	char *state_ls, *tmp;
2604	dbus_bool_t success = FALSE;
2605
2606	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
2607
2608	/* make state string lowercase to fit new DBus API convention
2609	 */
2610	state_ls = tmp = os_strdup(str_state);
2611	if (!tmp) {
2612		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2613		return FALSE;
2614	}
2615	while (*tmp) {
2616		*tmp = tolower(*tmp);
2617		tmp++;
2618	}
2619
2620	success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2621						   &state_ls, error);
2622
2623	os_free(state_ls);
2624
2625	return success;
2626}
2627
2628
2629/**
2630 * wpas_dbus_new_iface_get_scanning - Get interface scanning state
2631 * @iter: Pointer to incoming dbus message iter
2632 * @error: Location to store error on failure
2633 * @user_data: Function specific data
2634 * Returns: TRUE on success, FALSE on failure
2635 *
2636 * Getter for "scanning" property.
2637 */
2638dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
2639                                      void *user_data)
2640{
2641	struct wpa_supplicant *wpa_s = user_data;
2642	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
2643
2644	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2645						&scanning, error);
2646}
2647
2648
2649/**
2650 * wpas_dbus_getter_ap_scan - Control roaming mode
2651 * @iter: Pointer to incoming dbus message iter
2652 * @error: Location to store error on failure
2653 * @user_data: Function specific data
2654 * Returns: TRUE on success, FALSE on failure
2655 *
2656 * Getter function for "ApScan" property.
2657 */
2658dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
2659				     void *user_data)
2660{
2661	struct wpa_supplicant *wpa_s = user_data;
2662	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
2663
2664	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2665						&ap_scan, error);
2666}
2667
2668
2669/**
2670 * wpas_dbus_setter_ap_scan - Control roaming mode
2671 * @iter: Pointer to incoming dbus message iter
2672 * @error: Location to store error on failure
2673 * @user_data: Function specific data
2674 * Returns: TRUE on success, FALSE on failure
2675 *
2676 * Setter function for "ApScan" property.
2677 */
2678dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
2679				     void *user_data)
2680{
2681	struct wpa_supplicant *wpa_s = user_data;
2682	dbus_uint32_t ap_scan;
2683
2684	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2685					      &ap_scan))
2686		return FALSE;
2687
2688	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
2689		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2690				     "ap_scan must be 0, 1, or 2");
2691		return FALSE;
2692	}
2693	return TRUE;
2694}
2695
2696
2697/**
2698 * wpas_dbus_getter_fast_reauth - Control fast
2699 * reauthentication (TLS session resumption)
2700 * @iter: Pointer to incoming dbus message iter
2701 * @error: Location to store error on failure
2702 * @user_data: Function specific data
2703 * Returns: TRUE on success, FALSE on failure
2704 *
2705 * Getter function for "FastReauth" property.
2706 */
2707dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
2708					 DBusError *error,
2709					 void *user_data)
2710{
2711	struct wpa_supplicant *wpa_s = user_data;
2712	dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
2713
2714	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2715						&fast_reauth, error);
2716}
2717
2718
2719/**
2720 * wpas_dbus_setter_fast_reauth - Control fast
2721 * reauthentication (TLS session resumption)
2722 * @iter: Pointer to incoming dbus message iter
2723 * @error: Location to store error on failure
2724 * @user_data: Function specific data
2725 * Returns: TRUE on success, FALSE on failure
2726 *
2727 * Setter function for "FastReauth" property.
2728 */
2729dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
2730				     DBusError *error,
2731				     void *user_data)
2732{
2733	struct wpa_supplicant *wpa_s = user_data;
2734	dbus_bool_t fast_reauth;
2735
2736	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
2737					      &fast_reauth))
2738		return FALSE;
2739
2740	wpa_s->conf->fast_reauth = fast_reauth;
2741	return TRUE;
2742}
2743
2744
2745/**
2746 * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
2747 * @iter: Pointer to incoming dbus message iter
2748 * @error: Location to store error on failure
2749 * @user_data: Function specific data
2750 * Returns: TRUE on success, FALSE on failure
2751 *
2752 * Getter for "DisconnectReason" property.  The reason is negative if it is
2753 * locally generated.
2754 */
2755dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
2756					       DBusError *error,
2757					       void *user_data)
2758{
2759	struct wpa_supplicant *wpa_s = user_data;
2760	dbus_int32_t reason = wpa_s->disconnect_reason;
2761	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
2762						&reason, error);
2763}
2764
2765
2766/**
2767 * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
2768 * @iter: Pointer to incoming dbus message iter
2769 * @error: Location to store error on failure
2770 * @user_data: Function specific data
2771 * Returns: TRUE on success, FALSE on failure
2772 *
2773 * Getter function for "BSSExpireAge" property.
2774 */
2775dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
2776					    DBusError *error,
2777					    void *user_data)
2778{
2779	struct wpa_supplicant *wpa_s = user_data;
2780	dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
2781
2782	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2783						&expire_age, error);
2784}
2785
2786
2787/**
2788 * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
2789 * @iter: Pointer to incoming dbus message iter
2790 * @error: Location to store error on failure
2791 * @user_data: Function specific data
2792 * Returns: TRUE on success, FALSE on failure
2793 *
2794 * Setter function for "BSSExpireAge" property.
2795 */
2796dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
2797					    DBusError *error,
2798					    void *user_data)
2799{
2800	struct wpa_supplicant *wpa_s = user_data;
2801	dbus_uint32_t expire_age;
2802
2803	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2804					      &expire_age))
2805		return FALSE;
2806
2807	if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
2808		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2809				     "BSSExpireAge must be >= 10");
2810		return FALSE;
2811	}
2812	return TRUE;
2813}
2814
2815
2816/**
2817 * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
2818 * @iter: Pointer to incoming dbus message iter
2819 * @error: Location to store error on failure
2820 * @user_data: Function specific data
2821 * Returns: TRUE on success, FALSE on failure
2822 *
2823 * Getter function for "BSSExpireCount" property.
2824 */
2825dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
2826					      DBusError *error,
2827					      void *user_data)
2828{
2829	struct wpa_supplicant *wpa_s = user_data;
2830	dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
2831
2832	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2833						&expire_count, error);
2834}
2835
2836
2837/**
2838 * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
2839 * @iter: Pointer to incoming dbus message iter
2840 * @error: Location to store error on failure
2841 * @user_data: Function specific data
2842 * Returns: TRUE on success, FALSE on failure
2843 *
2844 * Setter function for "BSSExpireCount" property.
2845 */
2846dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
2847					      DBusError *error,
2848					      void *user_data)
2849{
2850	struct wpa_supplicant *wpa_s = user_data;
2851	dbus_uint32_t expire_count;
2852
2853	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2854					      &expire_count))
2855		return FALSE;
2856
2857	if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
2858		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2859				     "BSSExpireCount must be > 0");
2860		return FALSE;
2861	}
2862	return TRUE;
2863}
2864
2865
2866/**
2867 * wpas_dbus_getter_country - Control country code
2868 * @iter: Pointer to incoming dbus message iter
2869 * @error: Location to store error on failure
2870 * @user_data: Function specific data
2871 * Returns: TRUE on success, FALSE on failure
2872 *
2873 * Getter function for "Country" property.
2874 */
2875dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
2876				     void *user_data)
2877{
2878	struct wpa_supplicant *wpa_s = user_data;
2879	char country[3];
2880	char *str = country;
2881
2882	country[0] = wpa_s->conf->country[0];
2883	country[1] = wpa_s->conf->country[1];
2884	country[2] = '\0';
2885
2886	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2887						&str, error);
2888}
2889
2890
2891/**
2892 * wpas_dbus_setter_country - Control country code
2893 * @iter: Pointer to incoming dbus message iter
2894 * @error: Location to store error on failure
2895 * @user_data: Function specific data
2896 * Returns: TRUE on success, FALSE on failure
2897 *
2898 * Setter function for "Country" property.
2899 */
2900dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
2901				     void *user_data)
2902{
2903	struct wpa_supplicant *wpa_s = user_data;
2904	const char *country;
2905
2906	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
2907					      &country))
2908		return FALSE;
2909
2910	if (!country[0] || !country[1]) {
2911		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2912				     "invalid country code");
2913		return FALSE;
2914	}
2915
2916	if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
2917		wpa_printf(MSG_DEBUG, "Failed to set country");
2918		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2919				     "failed to set country code");
2920		return FALSE;
2921	}
2922
2923	wpa_s->conf->country[0] = country[0];
2924	wpa_s->conf->country[1] = country[1];
2925	return TRUE;
2926}
2927
2928
2929/**
2930 * wpas_dbus_getter_scan_interval - Get scan interval
2931 * @iter: Pointer to incoming dbus message iter
2932 * @error: Location to store error on failure
2933 * @user_data: Function specific data
2934 * Returns: TRUE on success, FALSE on failure
2935 *
2936 * Getter function for "ScanInterval" property.
2937 */
2938dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
2939					   DBusError *error,
2940					   void *user_data)
2941{
2942	struct wpa_supplicant *wpa_s = user_data;
2943	dbus_int32_t scan_interval = wpa_s->scan_interval;
2944
2945	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
2946						&scan_interval, error);
2947}
2948
2949
2950/**
2951 * wpas_dbus_setter_scan_interval - Control scan interval
2952 * @iter: Pointer to incoming dbus message iter
2953 * @error: Location to store error on failure
2954 * @user_data: Function specific data
2955 * Returns: TRUE on success, FALSE on failure
2956 *
2957 * Setter function for "ScanInterval" property.
2958 */
2959dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
2960					   DBusError *error,
2961					   void *user_data)
2962{
2963	struct wpa_supplicant *wpa_s = user_data;
2964	dbus_int32_t scan_interval;
2965
2966	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
2967					      &scan_interval))
2968		return FALSE;
2969
2970	if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
2971		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2972				     "scan_interval must be >= 0");
2973		return FALSE;
2974	}
2975	return TRUE;
2976}
2977
2978
2979/**
2980 * wpas_dbus_getter_ifname - Get interface name
2981 * @iter: Pointer to incoming dbus message iter
2982 * @error: Location to store error on failure
2983 * @user_data: Function specific data
2984 * Returns: TRUE on success, FALSE on failure
2985 *
2986 * Getter for "Ifname" property.
2987 */
2988dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
2989				    void *user_data)
2990{
2991	struct wpa_supplicant *wpa_s = user_data;
2992	const char *ifname = wpa_s->ifname;
2993
2994	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2995						&ifname, error);
2996}
2997
2998
2999/**
3000 * wpas_dbus_getter_driver - Get interface name
3001 * @iter: Pointer to incoming dbus message iter
3002 * @error: Location to store error on failure
3003 * @user_data: Function specific data
3004 * Returns: TRUE on success, FALSE on failure
3005 *
3006 * Getter for "Driver" property.
3007 */
3008dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
3009				    void *user_data)
3010{
3011	struct wpa_supplicant *wpa_s = user_data;
3012	const char *driver;
3013
3014	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
3015		wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
3016			   "wpa_s has no driver set");
3017		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
3018			       __func__);
3019		return FALSE;
3020	}
3021
3022	driver = wpa_s->driver->name;
3023	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3024						&driver, error);
3025}
3026
3027
3028/**
3029 * wpas_dbus_getter_current_bss - Get current bss object path
3030 * @iter: Pointer to incoming dbus message iter
3031 * @error: Location to store error on failure
3032 * @user_data: Function specific data
3033 * Returns: TRUE on success, FALSE on failure
3034 *
3035 * Getter for "CurrentBSS" property.
3036 */
3037dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
3038					 DBusError *error,
3039					 void *user_data)
3040{
3041	struct wpa_supplicant *wpa_s = user_data;
3042	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
3043
3044	if (wpa_s->current_bss)
3045		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3046			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3047			    wpa_s->dbus_new_path, wpa_s->current_bss->id);
3048	else
3049		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3050
3051	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3052						&bss_obj_path, error);
3053}
3054
3055
3056/**
3057 * wpas_dbus_getter_current_network - Get current network object path
3058 * @iter: Pointer to incoming dbus message iter
3059 * @error: Location to store error on failure
3060 * @user_data: Function specific data
3061 * Returns: TRUE on success, FALSE on failure
3062 *
3063 * Getter for "CurrentNetwork" property.
3064 */
3065dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
3066					     DBusError *error,
3067					     void *user_data)
3068{
3069	struct wpa_supplicant *wpa_s = user_data;
3070	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
3071
3072	if (wpa_s->current_ssid)
3073		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3074			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
3075			    wpa_s->dbus_new_path, wpa_s->current_ssid->id);
3076	else
3077		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3078
3079	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3080						&net_obj_path, error);
3081}
3082
3083
3084/**
3085 * wpas_dbus_getter_current_auth_mode - Get current authentication type
3086 * @iter: Pointer to incoming dbus message iter
3087 * @error: Location to store error on failure
3088 * @user_data: Function specific data
3089 * Returns: TRUE on success, FALSE on failure
3090 *
3091 * Getter for "CurrentAuthMode" property.
3092 */
3093dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
3094					       DBusError *error,
3095					       void *user_data)
3096{
3097	struct wpa_supplicant *wpa_s = user_data;
3098	const char *eap_mode;
3099	const char *auth_mode;
3100	char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
3101
3102	if (wpa_s->wpa_state != WPA_COMPLETED) {
3103		auth_mode = "INACTIVE";
3104	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
3105	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3106		eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
3107		os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
3108			    "EAP-%s", eap_mode);
3109		auth_mode = eap_mode_buf;
3110
3111	} else {
3112		auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
3113					     wpa_s->current_ssid->proto);
3114	}
3115
3116	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3117						&auth_mode, error);
3118}
3119
3120
3121/**
3122 * wpas_dbus_getter_bridge_ifname - Get interface name
3123 * @iter: Pointer to incoming dbus message iter
3124 * @error: Location to store error on failure
3125 * @user_data: Function specific data
3126 * Returns: TRUE on success, FALSE on failure
3127 *
3128 * Getter for "BridgeIfname" property.
3129 */
3130dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
3131					   DBusError *error,
3132					   void *user_data)
3133{
3134	struct wpa_supplicant *wpa_s = user_data;
3135	const char *bridge_ifname = wpa_s->bridge_ifname;
3136	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3137						&bridge_ifname, error);
3138}
3139
3140
3141/**
3142 * wpas_dbus_getter_bsss - Get array of BSSs objects
3143 * @iter: Pointer to incoming dbus message iter
3144 * @error: Location to store error on failure
3145 * @user_data: Function specific data
3146 * Returns: TRUE on success, FALSE on failure
3147 *
3148 * Getter for "BSSs" property.
3149 */
3150dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
3151				  void *user_data)
3152{
3153	struct wpa_supplicant *wpa_s = user_data;
3154	struct wpa_bss *bss;
3155	char **paths;
3156	unsigned int i = 0;
3157	dbus_bool_t success = FALSE;
3158
3159	paths = os_calloc(wpa_s->num_bss, sizeof(char *));
3160	if (!paths) {
3161		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3162		return FALSE;
3163	}
3164
3165	/* Loop through scan results and append each result's object path */
3166	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
3167		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3168		if (paths[i] == NULL) {
3169			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3170					     "no memory");
3171			goto out;
3172		}
3173		/* Construct the object path for this BSS. */
3174		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3175			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3176			    wpa_s->dbus_new_path, bss->id);
3177	}
3178
3179	success = wpas_dbus_simple_array_property_getter(iter,
3180							 DBUS_TYPE_OBJECT_PATH,
3181							 paths, wpa_s->num_bss,
3182							 error);
3183
3184out:
3185	while (i)
3186		os_free(paths[--i]);
3187	os_free(paths);
3188	return success;
3189}
3190
3191
3192/**
3193 * wpas_dbus_getter_networks - Get array of networks objects
3194 * @iter: Pointer to incoming dbus message iter
3195 * @error: Location to store error on failure
3196 * @user_data: Function specific data
3197 * Returns: TRUE on success, FALSE on failure
3198 *
3199 * Getter for "Networks" property.
3200 */
3201dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
3202				      void *user_data)
3203{
3204	struct wpa_supplicant *wpa_s = user_data;
3205	struct wpa_ssid *ssid;
3206	char **paths;
3207	unsigned int i = 0, num = 0;
3208	dbus_bool_t success = FALSE;
3209
3210	if (wpa_s->conf == NULL) {
3211		wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
3212			   "networks list.", __func__);
3213		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
3214			       "occurred getting the networks list", __func__);
3215		return FALSE;
3216	}
3217
3218	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
3219		if (!network_is_persistent_group(ssid))
3220			num++;
3221
3222	paths = os_calloc(num, sizeof(char *));
3223	if (!paths) {
3224		dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3225		return FALSE;
3226	}
3227
3228	/* Loop through configured networks and append object path of each */
3229	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
3230		if (network_is_persistent_group(ssid))
3231			continue;
3232		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3233		if (paths[i] == NULL) {
3234			dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3235			goto out;
3236		}
3237
3238		/* Construct the object path for this network. */
3239		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3240			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
3241			    wpa_s->dbus_new_path, ssid->id);
3242	}
3243
3244	success = wpas_dbus_simple_array_property_getter(iter,
3245							 DBUS_TYPE_OBJECT_PATH,
3246							 paths, num, error);
3247
3248out:
3249	while (i)
3250		os_free(paths[--i]);
3251	os_free(paths);
3252	return success;
3253}
3254
3255
3256/**
3257 * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
3258 * @iter: Pointer to incoming dbus message iter
3259 * @error: Location to store error on failure
3260 * @user_data: Function specific data
3261 * Returns: A dbus message containing the PKCS #11 engine path
3262 *
3263 * Getter for "PKCS11EnginePath" property.
3264 */
3265dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
3266						DBusError *error,
3267						void *user_data)
3268{
3269	struct wpa_supplicant *wpa_s = user_data;
3270	const char *pkcs11_engine_path;
3271
3272	if (wpa_s->conf == NULL) {
3273		wpa_printf(MSG_ERROR,
3274			   "wpas_dbus_getter_pkcs11_engine_path[dbus]: An "
3275			   "error occurred getting the PKCS #11 engine path.");
3276		dbus_set_error_const(
3277			error, DBUS_ERROR_FAILED,
3278			"An error occured getting the PKCS #11 engine path.");
3279		return FALSE;
3280	}
3281
3282	if (wpa_s->conf->pkcs11_engine_path == NULL)
3283		pkcs11_engine_path = "";
3284	else
3285		pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
3286	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3287						&pkcs11_engine_path, error);
3288}
3289
3290
3291/**
3292 * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
3293 * @iter: Pointer to incoming dbus message iter
3294 * @error: Location to store error on failure
3295 * @user_data: Function specific data
3296 * Returns: A dbus message containing the PKCS #11 module path
3297 *
3298 * Getter for "PKCS11ModulePath" property.
3299 */
3300dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
3301						DBusError *error,
3302						void *user_data)
3303{
3304	struct wpa_supplicant *wpa_s = user_data;
3305	const char *pkcs11_module_path;
3306
3307	if (wpa_s->conf == NULL) {
3308		wpa_printf(MSG_ERROR,
3309			   "wpas_dbus_getter_pkcs11_module_path[dbus]: An "
3310			   "error occurred getting the PKCS #11 module path.");
3311		dbus_set_error_const(
3312			error, DBUS_ERROR_FAILED,
3313			"An error occured getting the PKCS #11 module path.");
3314		return FALSE;
3315	}
3316
3317	if (wpa_s->conf->pkcs11_module_path == NULL)
3318		pkcs11_module_path = "";
3319	else
3320		pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
3321	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3322						&pkcs11_module_path, error);
3323}
3324
3325
3326/**
3327 * wpas_dbus_getter_blobs - Get all blobs defined for this interface
3328 * @iter: Pointer to incoming dbus message iter
3329 * @error: Location to store error on failure
3330 * @user_data: Function specific data
3331 * Returns: TRUE on success, FALSE on failure
3332 *
3333 * Getter for "Blobs" property.
3334 */
3335dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
3336				   void *user_data)
3337{
3338	struct wpa_supplicant *wpa_s = user_data;
3339	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
3340	struct wpa_config_blob *blob;
3341
3342	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3343					      "a{say}", &variant_iter) ||
3344	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
3345					      "{say}", &dict_iter)) {
3346		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3347		return FALSE;
3348	}
3349
3350	blob = wpa_s->conf->blobs;
3351	while (blob) {
3352		if (!dbus_message_iter_open_container(&dict_iter,
3353						      DBUS_TYPE_DICT_ENTRY,
3354						      NULL, &entry_iter) ||
3355		    !dbus_message_iter_append_basic(&entry_iter,
3356						    DBUS_TYPE_STRING,
3357						    &(blob->name)) ||
3358		    !dbus_message_iter_open_container(&entry_iter,
3359						      DBUS_TYPE_ARRAY,
3360						      DBUS_TYPE_BYTE_AS_STRING,
3361						      &array_iter) ||
3362		    !dbus_message_iter_append_fixed_array(&array_iter,
3363							  DBUS_TYPE_BYTE,
3364							  &(blob->data),
3365							  blob->len) ||
3366		    !dbus_message_iter_close_container(&entry_iter,
3367						       &array_iter) ||
3368		    !dbus_message_iter_close_container(&dict_iter,
3369						       &entry_iter)) {
3370			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3371					     "no memory");
3372			return FALSE;
3373		}
3374
3375		blob = blob->next;
3376	}
3377
3378	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
3379	    !dbus_message_iter_close_container(iter, &variant_iter)) {
3380		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3381		return FALSE;
3382	}
3383
3384	return TRUE;
3385}
3386
3387
3388static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
3389				       DBusError *error, const char *func_name)
3390{
3391	struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
3392
3393	if (!res) {
3394		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
3395		           func_name, args->id);
3396		dbus_set_error(error, DBUS_ERROR_FAILED,
3397			       "%s: BSS %d not found",
3398			       func_name, args->id);
3399	}
3400
3401	return res;
3402}
3403
3404
3405/**
3406 * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
3407 * @iter: Pointer to incoming dbus message iter
3408 * @error: Location to store error on failure
3409 * @user_data: Function specific data
3410 * Returns: TRUE on success, FALSE on failure
3411 *
3412 * Getter for "BSSID" property.
3413 */
3414dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
3415				       void *user_data)
3416{
3417	struct bss_handler_args *args = user_data;
3418	struct wpa_bss *res;
3419
3420	res = get_bss_helper(args, error, __func__);
3421	if (!res)
3422		return FALSE;
3423
3424	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3425						      res->bssid, ETH_ALEN,
3426						      error);
3427}
3428
3429
3430/**
3431 * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
3432 * @iter: Pointer to incoming dbus message iter
3433 * @error: Location to store error on failure
3434 * @user_data: Function specific data
3435 * Returns: TRUE on success, FALSE on failure
3436 *
3437 * Getter for "SSID" property.
3438 */
3439dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
3440				      void *user_data)
3441{
3442	struct bss_handler_args *args = user_data;
3443	struct wpa_bss *res;
3444
3445	res = get_bss_helper(args, error, __func__);
3446	if (!res)
3447		return FALSE;
3448
3449	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3450						      res->ssid, res->ssid_len,
3451						      error);
3452}
3453
3454
3455/**
3456 * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
3457 * @iter: Pointer to incoming dbus message iter
3458 * @error: Location to store error on failure
3459 * @user_data: Function specific data
3460 * Returns: TRUE on success, FALSE on failure
3461 *
3462 * Getter for "Privacy" property.
3463 */
3464dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
3465					 DBusError *error, void *user_data)
3466{
3467	struct bss_handler_args *args = user_data;
3468	struct wpa_bss *res;
3469	dbus_bool_t privacy;
3470
3471	res = get_bss_helper(args, error, __func__);
3472	if (!res)
3473		return FALSE;
3474
3475	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
3476	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3477						&privacy, error);
3478}
3479
3480
3481/**
3482 * wpas_dbus_getter_bss_mode - Return the mode of a BSS
3483 * @iter: Pointer to incoming dbus message iter
3484 * @error: Location to store error on failure
3485 * @user_data: Function specific data
3486 * Returns: TRUE on success, FALSE on failure
3487 *
3488 * Getter for "Mode" property.
3489 */
3490dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
3491				      void *user_data)
3492{
3493	struct bss_handler_args *args = user_data;
3494	struct wpa_bss *res;
3495	const char *mode;
3496
3497	res = get_bss_helper(args, error, __func__);
3498	if (!res)
3499		return FALSE;
3500
3501	if (res->caps & IEEE80211_CAP_IBSS)
3502		mode = "ad-hoc";
3503	else
3504		mode = "infrastructure";
3505
3506	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3507						&mode, error);
3508}
3509
3510
3511/**
3512 * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
3513 * @iter: Pointer to incoming dbus message iter
3514 * @error: Location to store error on failure
3515 * @user_data: Function specific data
3516 * Returns: TRUE on success, FALSE on failure
3517 *
3518 * Getter for "Level" property.
3519 */
3520dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
3521					DBusError *error, void *user_data)
3522{
3523	struct bss_handler_args *args = user_data;
3524	struct wpa_bss *res;
3525	s16 level;
3526
3527	res = get_bss_helper(args, error, __func__);
3528	if (!res)
3529		return FALSE;
3530
3531	level = (s16) res->level;
3532	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
3533						&level, error);
3534}
3535
3536
3537/**
3538 * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
3539 * @iter: Pointer to incoming dbus message iter
3540 * @error: Location to store error on failure
3541 * @user_data: Function specific data
3542 * Returns: TRUE on success, FALSE on failure
3543 *
3544 * Getter for "Frequency" property.
3545 */
3546dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
3547					   DBusError *error, void *user_data)
3548{
3549	struct bss_handler_args *args = user_data;
3550	struct wpa_bss *res;
3551	u16 freq;
3552
3553	res = get_bss_helper(args, error, __func__);
3554	if (!res)
3555		return FALSE;
3556
3557	freq = (u16) res->freq;
3558	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
3559						&freq, error);
3560}
3561
3562
3563static int cmp_u8s_desc(const void *a, const void *b)
3564{
3565	return (*(u8 *) b - *(u8 *) a);
3566}
3567
3568
3569/**
3570 * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
3571 * @iter: Pointer to incoming dbus message iter
3572 * @error: Location to store error on failure
3573 * @user_data: Function specific data
3574 * Returns: TRUE on success, FALSE on failure
3575 *
3576 * Getter for "Rates" property.
3577 */
3578dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
3579				       DBusError *error, void *user_data)
3580{
3581	struct bss_handler_args *args = user_data;
3582	struct wpa_bss *res;
3583	u8 *ie_rates = NULL;
3584	u32 *real_rates;
3585	int rates_num, i;
3586	dbus_bool_t success = FALSE;
3587
3588	res = get_bss_helper(args, error, __func__);
3589	if (!res)
3590		return FALSE;
3591
3592	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
3593	if (rates_num < 0)
3594		return FALSE;
3595
3596	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
3597
3598	real_rates = os_malloc(sizeof(u32) * rates_num);
3599	if (!real_rates) {
3600		os_free(ie_rates);
3601		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3602		return FALSE;
3603	}
3604
3605	for (i = 0; i < rates_num; i++)
3606		real_rates[i] = ie_rates[i] * 500000;
3607
3608	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
3609							 real_rates, rates_num,
3610							 error);
3611
3612	os_free(ie_rates);
3613	os_free(real_rates);
3614	return success;
3615}
3616
3617
3618static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
3619						   struct wpa_ie_data *ie_data,
3620						   DBusError *error)
3621{
3622	DBusMessageIter iter_dict, variant_iter;
3623	const char *group;
3624	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
3625	const char *key_mgmt[7]; /* max 7 key managements may be supported */
3626	int n;
3627
3628	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3629					      "a{sv}", &variant_iter))
3630		goto nomem;
3631
3632	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3633		goto nomem;
3634
3635	/* KeyMgmt */
3636	n = 0;
3637	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
3638		key_mgmt[n++] = "wpa-psk";
3639	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
3640		key_mgmt[n++] = "wpa-ft-psk";
3641	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
3642		key_mgmt[n++] = "wpa-psk-sha256";
3643	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
3644		key_mgmt[n++] = "wpa-eap";
3645	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
3646		key_mgmt[n++] = "wpa-ft-eap";
3647	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
3648		key_mgmt[n++] = "wpa-eap-sha256";
3649	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
3650		key_mgmt[n++] = "wpa-none";
3651
3652	if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
3653					       key_mgmt, n))
3654		goto nomem;
3655
3656	/* Group */
3657	switch (ie_data->group_cipher) {
3658	case WPA_CIPHER_WEP40:
3659		group = "wep40";
3660		break;
3661	case WPA_CIPHER_TKIP:
3662		group = "tkip";
3663		break;
3664	case WPA_CIPHER_CCMP:
3665		group = "ccmp";
3666		break;
3667	case WPA_CIPHER_GCMP:
3668		group = "gcmp";
3669		break;
3670	case WPA_CIPHER_WEP104:
3671		group = "wep104";
3672		break;
3673	case WPA_CIPHER_CCMP_256:
3674		group = "ccmp-256";
3675		break;
3676	case WPA_CIPHER_GCMP_256:
3677		group = "gcmp-256";
3678		break;
3679	default:
3680		group = "";
3681		break;
3682	}
3683
3684	if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
3685		goto nomem;
3686
3687	/* Pairwise */
3688	n = 0;
3689	if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
3690		pairwise[n++] = "tkip";
3691	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
3692		pairwise[n++] = "ccmp";
3693	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
3694		pairwise[n++] = "gcmp";
3695	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
3696		pairwise[n++] = "ccmp-256";
3697	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
3698		pairwise[n++] = "gcmp-256";
3699
3700	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
3701					       pairwise, n))
3702		goto nomem;
3703
3704	/* Management group (RSN only) */
3705	if (ie_data->proto == WPA_PROTO_RSN) {
3706		switch (ie_data->mgmt_group_cipher) {
3707#ifdef CONFIG_IEEE80211W
3708		case WPA_CIPHER_AES_128_CMAC:
3709			group = "aes128cmac";
3710			break;
3711#endif /* CONFIG_IEEE80211W */
3712		default:
3713			group = "";
3714			break;
3715		}
3716
3717		if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
3718						 group))
3719			goto nomem;
3720	}
3721
3722	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
3723		goto nomem;
3724	if (!dbus_message_iter_close_container(iter, &variant_iter))
3725		goto nomem;
3726
3727	return TRUE;
3728
3729nomem:
3730	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3731	return FALSE;
3732}
3733
3734
3735/**
3736 * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
3737 * @iter: Pointer to incoming dbus message iter
3738 * @error: Location to store error on failure
3739 * @user_data: Function specific data
3740 * Returns: TRUE on success, FALSE on failure
3741 *
3742 * Getter for "WPA" property.
3743 */
3744dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
3745				     void *user_data)
3746{
3747	struct bss_handler_args *args = user_data;
3748	struct wpa_bss *res;
3749	struct wpa_ie_data wpa_data;
3750	const u8 *ie;
3751
3752	res = get_bss_helper(args, error, __func__);
3753	if (!res)
3754		return FALSE;
3755
3756	os_memset(&wpa_data, 0, sizeof(wpa_data));
3757	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
3758	if (ie) {
3759		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3760			dbus_set_error_const(error, DBUS_ERROR_FAILED,
3761					     "failed to parse WPA IE");
3762			return FALSE;
3763		}
3764	}
3765
3766	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3767}
3768
3769
3770/**
3771 * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
3772 * @iter: Pointer to incoming dbus message iter
3773 * @error: Location to store error on failure
3774 * @user_data: Function specific data
3775 * Returns: TRUE on success, FALSE on failure
3776 *
3777 * Getter for "RSN" property.
3778 */
3779dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
3780				     void *user_data)
3781{
3782	struct bss_handler_args *args = user_data;
3783	struct wpa_bss *res;
3784	struct wpa_ie_data wpa_data;
3785	const u8 *ie;
3786
3787	res = get_bss_helper(args, error, __func__);
3788	if (!res)
3789		return FALSE;
3790
3791	os_memset(&wpa_data, 0, sizeof(wpa_data));
3792	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
3793	if (ie) {
3794		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3795			dbus_set_error_const(error, DBUS_ERROR_FAILED,
3796					     "failed to parse RSN IE");
3797			return FALSE;
3798		}
3799	}
3800
3801	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3802}
3803
3804
3805/**
3806 * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
3807 * @iter: Pointer to incoming dbus message iter
3808 * @error: Location to store error on failure
3809 * @user_data: Function specific data
3810 * Returns: TRUE on success, FALSE on failure
3811 *
3812 * Getter for "WPS" property.
3813 */
3814dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
3815				     void *user_data)
3816{
3817	struct bss_handler_args *args = user_data;
3818	struct wpa_bss *res;
3819#ifdef CONFIG_WPS
3820	struct wpabuf *wps_ie;
3821#endif /* CONFIG_WPS */
3822	DBusMessageIter iter_dict, variant_iter;
3823	const char *type = "";
3824
3825	res = get_bss_helper(args, error, __func__);
3826	if (!res)
3827		return FALSE;
3828
3829	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3830					      "a{sv}", &variant_iter))
3831		goto nomem;
3832
3833	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3834		goto nomem;
3835
3836#ifdef CONFIG_WPS
3837	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
3838	if (wps_ie) {
3839		if (wps_is_selected_pbc_registrar(wps_ie))
3840			type = "pbc";
3841		else if (wps_is_selected_pin_registrar(wps_ie))
3842			type = "pin";
3843	}
3844#endif /* CONFIG_WPS */
3845
3846	if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
3847		goto nomem;
3848
3849	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
3850		goto nomem;
3851	if (!dbus_message_iter_close_container(iter, &variant_iter))
3852		goto nomem;
3853
3854	return TRUE;
3855
3856nomem:
3857	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3858	return FALSE;
3859}
3860
3861
3862/**
3863 * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
3864 * @iter: Pointer to incoming dbus message iter
3865 * @error: Location to store error on failure
3866 * @user_data: Function specific data
3867 * Returns: TRUE on success, FALSE on failure
3868 *
3869 * Getter for "IEs" property.
3870 */
3871dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
3872				     void *user_data)
3873{
3874	struct bss_handler_args *args = user_data;
3875	struct wpa_bss *res;
3876
3877	res = get_bss_helper(args, error, __func__);
3878	if (!res)
3879		return FALSE;
3880
3881	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3882						      res + 1, res->ie_len,
3883						      error);
3884}
3885
3886
3887/**
3888 * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
3889 * @iter: Pointer to incoming dbus message iter
3890 * @error: Location to store error on failure
3891 * @user_data: Function specific data
3892 * Returns: TRUE on success, FALSE on failure
3893 *
3894 * Getter for "enabled" property of a configured network.
3895 */
3896dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
3897				     void *user_data)
3898{
3899	struct network_handler_args *net = user_data;
3900	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
3901
3902	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3903						&enabled, error);
3904}
3905
3906
3907/**
3908 * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
3909 * @iter: Pointer to incoming dbus message iter
3910 * @error: Location to store error on failure
3911 * @user_data: Function specific data
3912 * Returns: TRUE on success, FALSE on failure
3913 *
3914 * Setter for "Enabled" property of a configured network.
3915 */
3916dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
3917				     void *user_data)
3918{
3919	struct network_handler_args *net = user_data;
3920	struct wpa_supplicant *wpa_s;
3921	struct wpa_ssid *ssid;
3922	dbus_bool_t enable;
3923
3924	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
3925					      &enable))
3926		return FALSE;
3927
3928	wpa_s = net->wpa_s;
3929	ssid = net->ssid;
3930
3931	if (enable)
3932		wpa_supplicant_enable_network(wpa_s, ssid);
3933	else
3934		wpa_supplicant_disable_network(wpa_s, ssid);
3935
3936	return TRUE;
3937}
3938
3939
3940/**
3941 * wpas_dbus_getter_network_properties - Get options for a configured network
3942 * @iter: Pointer to incoming dbus message iter
3943 * @error: Location to store error on failure
3944 * @user_data: Function specific data
3945 * Returns: TRUE on success, FALSE on failure
3946 *
3947 * Getter for "Properties" property of a configured network.
3948 */
3949dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
3950						DBusError *error,
3951						void *user_data)
3952{
3953	struct network_handler_args *net = user_data;
3954	DBusMessageIter	variant_iter, dict_iter;
3955	char **iterator;
3956	char **props = wpa_config_get_all(net->ssid, 1);
3957	dbus_bool_t success = FALSE;
3958
3959	if (!props) {
3960		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3961		return FALSE;
3962	}
3963
3964	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
3965					      &variant_iter) ||
3966	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
3967		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3968		goto out;
3969	}
3970
3971	iterator = props;
3972	while (*iterator) {
3973		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
3974						 *(iterator + 1))) {
3975			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3976					     "no memory");
3977			goto out;
3978		}
3979		iterator += 2;
3980	}
3981
3982
3983	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
3984	    !dbus_message_iter_close_container(iter, &variant_iter)) {
3985		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3986		goto out;
3987	}
3988
3989	success = TRUE;
3990
3991out:
3992	iterator = props;
3993	while (*iterator) {
3994		os_free(*iterator);
3995		iterator++;
3996	}
3997	os_free(props);
3998	return success;
3999}
4000
4001
4002/**
4003 * wpas_dbus_setter_network_properties - Set options for a configured network
4004 * @iter: Pointer to incoming dbus message iter
4005 * @error: Location to store error on failure
4006 * @user_data: Function specific data
4007 * Returns: TRUE on success, FALSE on failure
4008 *
4009 * Setter for "Properties" property of a configured network.
4010 */
4011dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
4012						DBusError *error,
4013						void *user_data)
4014{
4015	struct network_handler_args *net = user_data;
4016	struct wpa_ssid *ssid = net->ssid;
4017	DBusMessageIter	variant_iter;
4018
4019	dbus_message_iter_recurse(iter, &variant_iter);
4020	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
4021}
4022
4023
4024#ifdef CONFIG_AP
4025
4026DBusMessage * wpas_dbus_handler_subscribe_preq(
4027	DBusMessage *message, struct wpa_supplicant *wpa_s)
4028{
4029	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4030	char *name;
4031
4032	if (wpa_s->preq_notify_peer != NULL) {
4033		if (os_strcmp(dbus_message_get_sender(message),
4034			      wpa_s->preq_notify_peer) == 0)
4035			return NULL;
4036
4037		return dbus_message_new_error(message,
4038			WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
4039			"Another application is already subscribed");
4040	}
4041
4042	name = os_strdup(dbus_message_get_sender(message));
4043	if (!name)
4044		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
4045					      "out of memory");
4046
4047	wpa_s->preq_notify_peer = name;
4048
4049	/* Subscribe to clean up if application closes socket */
4050	wpas_dbus_subscribe_noc(priv);
4051
4052	/*
4053	 * Double-check it's still alive to make sure that we didn't
4054	 * miss the NameOwnerChanged signal, e.g. while strdup'ing.
4055	 */
4056	if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
4057		/*
4058		 * Application no longer exists, clean up.
4059		 * The return value is irrelevant now.
4060		 *
4061		 * Need to check if the NameOwnerChanged handling
4062		 * already cleaned up because we have processed
4063		 * DBus messages while checking if the name still
4064		 * has an owner.
4065		 */
4066		if (!wpa_s->preq_notify_peer)
4067			return NULL;
4068		os_free(wpa_s->preq_notify_peer);
4069		wpa_s->preq_notify_peer = NULL;
4070		wpas_dbus_unsubscribe_noc(priv);
4071	}
4072
4073	return NULL;
4074}
4075
4076
4077DBusMessage * wpas_dbus_handler_unsubscribe_preq(
4078	DBusMessage *message, struct wpa_supplicant *wpa_s)
4079{
4080	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4081
4082	if (!wpa_s->preq_notify_peer)
4083		return dbus_message_new_error(message,
4084			WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
4085			"Not subscribed");
4086
4087	if (os_strcmp(wpa_s->preq_notify_peer,
4088		      dbus_message_get_sender(message)))
4089		return dbus_message_new_error(message,
4090			WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
4091			"Can't unsubscribe others");
4092
4093	os_free(wpa_s->preq_notify_peer);
4094	wpa_s->preq_notify_peer = NULL;
4095	wpas_dbus_unsubscribe_noc(priv);
4096	return NULL;
4097}
4098
4099
4100void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
4101			   const u8 *addr, const u8 *dst, const u8 *bssid,
4102			   const u8 *ie, size_t ie_len, u32 ssi_signal)
4103{
4104	DBusMessage *msg;
4105	DBusMessageIter iter, dict_iter;
4106	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4107
4108	/* Do nothing if the control interface is not turned on */
4109	if (priv == NULL)
4110		return;
4111
4112	if (wpa_s->preq_notify_peer == NULL)
4113		return;
4114
4115	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
4116				      WPAS_DBUS_NEW_IFACE_INTERFACE,
4117				      "ProbeRequest");
4118	if (msg == NULL)
4119		return;
4120
4121	dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
4122
4123	dbus_message_iter_init_append(msg, &iter);
4124
4125	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
4126		goto fail;
4127	if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
4128						     (const char *) addr,
4129						     ETH_ALEN))
4130		goto fail;
4131	if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
4132						    (const char *) dst,
4133						    ETH_ALEN))
4134		goto fail;
4135	if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
4136						      (const char *) bssid,
4137						      ETH_ALEN))
4138		goto fail;
4139	if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
4140							     (const char *) ie,
4141							     ie_len))
4142		goto fail;
4143	if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
4144						      ssi_signal))
4145		goto fail;
4146	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
4147		goto fail;
4148
4149	dbus_connection_send(priv->con, msg, NULL);
4150	goto out;
4151fail:
4152	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
4153out:
4154	dbus_message_unref(msg);
4155}
4156
4157#endif /* CONFIG_AP */
4158