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