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