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