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