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