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