• 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_allow_roam(DBusMessage * message,DBusMessageIter * var,dbus_bool_t * allow,DBusMessage ** reply)1597 static int wpas_dbus_get_scan_allow_roam(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 = 1;
1633 
1634 	os_memset(&params, 0, sizeof(params));
1635 
1636 	dbus_message_iter_init(message, &iter);
1637 
1638 	dbus_message_iter_recurse(&iter, &dict_iter);
1639 
1640 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
1641 	       DBUS_TYPE_DICT_ENTRY) {
1642 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
1643 		dbus_message_iter_get_basic(&entry_iter, &key);
1644 		dbus_message_iter_next(&entry_iter);
1645 		dbus_message_iter_recurse(&entry_iter, &variant_iter);
1646 
1647 		if (os_strcmp(key, "Type") == 0) {
1648 			if (wpas_dbus_get_scan_type(message, &variant_iter,
1649 						    &type, &reply) < 0)
1650 				goto out;
1651 		} else if (os_strcmp(key, "SSIDs") == 0) {
1652 			if (wpas_dbus_get_scan_ssids(message, &variant_iter,
1653 						     &params, &reply) < 0)
1654 				goto out;
1655 		} else if (os_strcmp(key, "IEs") == 0) {
1656 			if (wpas_dbus_get_scan_ies(message, &variant_iter,
1657 						   &params, &reply) < 0)
1658 				goto out;
1659 		} else if (os_strcmp(key, "Channels") == 0) {
1660 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
1661 							&params, &reply) < 0)
1662 				goto out;
1663 		} else if (os_strcmp(key, "AllowRoam") == 0) {
1664 			if (wpas_dbus_get_scan_allow_roam(message,
1665 							  &variant_iter,
1666 							  &allow_roam,
1667 							  &reply) < 0)
1668 				goto out;
1669 		} else {
1670 			wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
1671 				   __func__, key);
1672 			reply = wpas_dbus_error_invalid_args(message, key);
1673 			goto out;
1674 		}
1675 
1676 		dbus_message_iter_next(&dict_iter);
1677 	}
1678 
1679 	if (!type) {
1680 		wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
1681 			   __func__);
1682 		reply = wpas_dbus_error_invalid_args(message, key);
1683 		goto out;
1684 	}
1685 
1686 	if (os_strcmp(type, "passive") == 0) {
1687 		if (params.num_ssids || params.extra_ies_len) {
1688 			wpa_printf(MSG_DEBUG,
1689 				   "%s[dbus]: SSIDs or IEs specified for passive scan.",
1690 				   __func__);
1691 			reply = wpas_dbus_error_invalid_args(
1692 				message,
1693 				"You can specify only Channels in passive scan");
1694 			goto out;
1695 		} else {
1696 			if (wpa_s->sched_scanning) {
1697 				wpa_printf(MSG_DEBUG,
1698 					   "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1699 					   __func__);
1700 				wpa_supplicant_cancel_sched_scan(wpa_s);
1701 			}
1702 
1703 			if (params.freqs && params.freqs[0]) {
1704 				wpa_s->last_scan_req = MANUAL_SCAN_REQ;
1705 				if (wpa_supplicant_trigger_scan(wpa_s,
1706 								&params)) {
1707 					reply = wpas_dbus_error_scan_error(
1708 						message,
1709 						"Scan request rejected");
1710 				}
1711 			} else {
1712 				wpa_s->scan_req = MANUAL_SCAN_REQ;
1713 				wpa_supplicant_req_scan(wpa_s, 0, 0);
1714 			}
1715 		}
1716 	} else if (os_strcmp(type, "active") == 0) {
1717 		if (!params.num_ssids) {
1718 			/* Add wildcard ssid */
1719 			params.num_ssids++;
1720 		}
1721 #ifdef CONFIG_AUTOSCAN
1722 		autoscan_deinit(wpa_s);
1723 #endif /* CONFIG_AUTOSCAN */
1724 		if (wpa_s->sched_scanning) {
1725 			wpa_printf(MSG_DEBUG,
1726 				   "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1727 				   __func__);
1728 			wpa_supplicant_cancel_sched_scan(wpa_s);
1729 		}
1730 
1731 		wpa_s->last_scan_req = MANUAL_SCAN_REQ;
1732 		if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1733 			reply = wpas_dbus_error_scan_error(
1734 				message, "Scan request rejected");
1735 		}
1736 	} else {
1737 		wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
1738 			   __func__, type);
1739 		reply = wpas_dbus_error_invalid_args(message,
1740 						     "Wrong scan type");
1741 		goto out;
1742 	}
1743 
1744 	if (!allow_roam)
1745 		wpa_s->scan_res_handler = scan_only_handler;
1746 
1747 out:
1748 	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
1749 		os_free((u8 *) params.ssids[i].ssid);
1750 	os_free((u8 *) params.extra_ies);
1751 	os_free(params.freqs);
1752 	return reply;
1753 }
1754 
1755 
1756 /*
1757  * wpas_dbus_handler_abort_scan - Request an ongoing scan to be aborted
1758  * @message: Pointer to incoming dbus message
1759  * @wpa_s: wpa_supplicant structure for a network interface
1760  * Returns: Abort failed or no scan in progress DBus error message on failure
1761  * or NULL otherwise.
1762  *
1763  * Handler function for "AbortScan" method call of network interface.
1764  */
wpas_dbus_handler_abort_scan(DBusMessage * message,struct wpa_supplicant * wpa_s)1765 DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message,
1766 					   struct wpa_supplicant *wpa_s)
1767 {
1768 	if (wpas_abort_ongoing_scan(wpa_s) < 0)
1769 		return dbus_message_new_error(
1770 			message, WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
1771 			"Abort failed or no scan in progress");
1772 
1773 	return NULL;
1774 }
1775 
1776 
1777 /**
1778  * wpas_dbus_new_iface_add_cred - Add a new credential
1779  * @message: Pointer to incoming dbus message
1780  * @wpa_s: wpa_supplicant structure for a network interface
1781  * Returns: A dbus message containing the object path of the new credential
1782  *
1783  * Handler function for "AddCred" method call of a network interface.
1784  */
wpas_dbus_handler_add_cred(DBusMessage * message,struct wpa_supplicant * wpa_s)1785 DBusMessage * wpas_dbus_handler_add_cred(DBusMessage *message,
1786 					 struct wpa_supplicant *wpa_s)
1787 {
1788 	DBusMessage *reply = NULL;
1789 	DBusMessageIter	iter;
1790 	struct wpa_cred *cred = NULL;
1791 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1792 	DBusError error;
1793 
1794 	dbus_message_iter_init(message, &iter);
1795 
1796 	if (wpa_s->dbus_new_path)
1797 		cred = wpa_config_add_cred(wpa_s->conf);
1798 	if (!cred) {
1799 		wpa_printf(MSG_ERROR, "%s[dbus]: can't add new credential.",
1800 			   __func__);
1801 		reply = wpas_dbus_error_unknown_error(
1802 			message,
1803 			"wpa_supplicant could not add a credential on this interface.");
1804 		goto err;
1805 	}
1806 
1807 	dbus_error_init(&error);
1808 	if (!set_cred_properties(wpa_s, cred, &iter, &error)) {
1809 		wpa_printf(MSG_DEBUG,
1810 			   "%s[dbus]: control interface couldn't set credential properties",
1811 			   __func__);
1812 		reply = wpas_dbus_reply_new_from_error(message, &error,
1813 						       DBUS_ERROR_INVALID_ARGS,
1814 						       "Failed to add credential");
1815 		dbus_error_free(&error);
1816 		goto err;
1817 	}
1818 
1819 	/* Construct the object path for this network. */
1820 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1821 		    "%s/" WPAS_DBUS_NEW_CREDENTIALS_PART "/%d",
1822 		    wpa_s->dbus_new_path, cred->id);
1823 
1824 	reply = dbus_message_new_method_return(message);
1825 	if (!reply) {
1826 		reply = wpas_dbus_error_no_memory(message);
1827 		goto err;
1828 	}
1829 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1830 				      DBUS_TYPE_INVALID)) {
1831 		dbus_message_unref(reply);
1832 		reply = wpas_dbus_error_no_memory(message);
1833 		goto err;
1834 	}
1835 
1836 	return reply;
1837 
1838 err:
1839 	if (cred)
1840 		wpa_config_remove_cred(wpa_s->conf, cred->id);
1841 	return reply;
1842 }
1843 
1844 
1845 /**
1846  * wpas_dbus_handler_remove_cred - Remove a configured credential
1847  * @message: Pointer to incoming dbus message
1848  * @wpa_s: wpa_supplicant structure for a network interface
1849  * Returns: NULL on success or dbus error on failure
1850  *
1851  * Handler function for "RemoveCred" method call of a network interface.
1852  */
wpas_dbus_handler_remove_cred(DBusMessage * message,struct wpa_supplicant * wpa_s)1853 DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message,
1854 					    struct wpa_supplicant *wpa_s)
1855 {
1856 	DBusMessage *reply = NULL;
1857 	const char *op;
1858 	char *iface, *cred_id;
1859 	int id;
1860 	struct wpa_cred *cred;
1861 
1862 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1863 			      DBUS_TYPE_INVALID);
1864 
1865 	/* Extract the network ID and ensure the network is actually a child of
1866 	 * this interface */
1867 	iface = wpas_dbus_new_decompose_object_path(
1868 		op, WPAS_DBUS_NEW_CREDENTIALS_PART, &cred_id);
1869 	if (!iface || !cred_id || !wpa_s->dbus_new_path ||
1870 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1871 		reply = wpas_dbus_error_invalid_args(message, op);
1872 		goto out;
1873 	}
1874 
1875 	errno = 0;
1876 	id = strtoul(cred_id, NULL, 10);
1877 	if (errno != 0) {
1878 		reply = wpas_dbus_error_invalid_args(message, op);
1879 		goto out;
1880 	}
1881 
1882 	cred = wpa_config_get_cred(wpa_s->conf, id);
1883 	if (!cred) {
1884 		wpa_printf(MSG_ERROR, "%s[dbus]: could not find credential %s",
1885 			   __func__, op);
1886 		reply = wpas_dbus_error_invalid_args(
1887 			message, "could not find credential");
1888 		goto out;
1889 	}
1890 
1891 	if (wpas_remove_cred(wpa_s, cred) < 0) {
1892 		wpa_printf(MSG_ERROR,
1893 			   "%s[dbus]: error occurred when removing cred %d",
1894 			   __func__, id);
1895 		reply = wpas_dbus_error_unknown_error(
1896 			message,
1897 			"error removing the specified credential on its interface.");
1898 		goto out;
1899 	}
1900 
1901 out:
1902 	os_free(iface);
1903 	return reply;
1904 }
1905 
1906 
1907 /**
1908  * wpas_dbus_handler_remove_all_creds - Remove all the configured credentials
1909  * @message: Pointer to incoming dbus message
1910  * @wpa_s: wpa_supplicant structure for a network interface
1911  * Returns: NULL indicating success or DBus error message on failure
1912  *
1913  * Handler function for "RemoveAllCreds" method call of a network interface.
1914  */
wpas_dbus_handler_remove_all_creds(DBusMessage * message,struct wpa_supplicant * wpa_s)1915 DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message,
1916 						 struct wpa_supplicant *wpa_s)
1917 {
1918 	int res;
1919 	DBusMessage *reply = NULL;
1920 
1921 	res = wpas_remove_all_creds(wpa_s);
1922 	if (res < 0) {
1923 		wpa_printf(MSG_ERROR,
1924 			   "%s[dbus]: failed to remove all credentials",
1925 			   __func__);
1926 		reply = wpas_dbus_error_unknown_error(
1927 			message, "failed to remove all credentials");
1928 	}
1929 
1930 	return reply;
1931 }
1932 
1933 
1934 #ifdef CONFIG_INTERWORKING
1935 DBusMessage *
wpas_dbus_handler_interworking_select(DBusMessage * message,struct wpa_supplicant * wpa_s)1936 wpas_dbus_handler_interworking_select(DBusMessage *message,
1937 				      struct wpa_supplicant *wpa_s)
1938 {
1939 	int result;
1940 	DBusMessage *reply = NULL;
1941 
1942 	/* Automatic selection is disabled and no constraint on channels */
1943 	result = interworking_select(wpa_s, 0, NULL);
1944 	if (result < 0) {
1945 		wpa_printf(MSG_ERROR,
1946 			   "%s[dbus]: failed to start Interworking selection",
1947 			   __func__);
1948 		reply = wpas_dbus_error_scan_error(
1949 			message,
1950 			"error starting Interworking selection.");
1951 	}
1952 
1953 	return reply;
1954 }
1955 #endif /* CONFIG_INTERWORKING */
1956 
1957 
1958 /**
1959  * wpas_dbus_handler_signal_poll - Request immediate signal properties
1960  * @message: Pointer to incoming dbus message
1961  * @wpa_s: wpa_supplicant structure for a network interface
1962  * Returns: NULL indicating success or DBus error message on failure
1963  *
1964  * Handler function for "SignalPoll" method call of a network device. Requests
1965  * that wpa_supplicant read signal properties like RSSI, noise, and link
1966  * speed and return them.
1967  */
wpas_dbus_handler_signal_poll(DBusMessage * message,struct wpa_supplicant * wpa_s)1968 DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
1969 					    struct wpa_supplicant *wpa_s)
1970 {
1971 	struct wpa_signal_info si;
1972 	DBusMessage *reply = NULL;
1973 	DBusMessageIter iter;
1974 	int ret;
1975 
1976 	ret = wpa_drv_signal_poll(wpa_s, &si);
1977 	if (ret) {
1978 		return dbus_message_new_error(message, DBUS_ERROR_FAILED,
1979 					      "Failed to read signal");
1980 	}
1981 
1982 	reply = dbus_message_new_method_return(message);
1983 	if (reply == NULL)
1984 		goto nomem;
1985 
1986 	dbus_message_iter_init_append(reply, &iter);
1987 
1988 	if (wpas_dbus_new_from_signal_information(&iter, &si) != 0)
1989 		goto nomem;
1990 
1991 	return reply;
1992 
1993 nomem:
1994 	if (reply)
1995 		dbus_message_unref(reply);
1996 	return wpas_dbus_error_no_memory(message);
1997 }
1998 
1999 
2000 /*
2001  * wpas_dbus_handler_disconnect - Terminate the current connection
2002  * @message: Pointer to incoming dbus message
2003  * @wpa_s: wpa_supplicant structure for a network interface
2004  * Returns: NotConnected DBus error message if already not connected
2005  * or NULL otherwise.
2006  *
2007  * Handler function for "Disconnect" method call of network interface.
2008  */
wpas_dbus_handler_disconnect(DBusMessage * message,struct wpa_supplicant * wpa_s)2009 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
2010 					   struct wpa_supplicant *wpa_s)
2011 {
2012 	if (wpa_s->current_ssid != NULL) {
2013 		wpas_request_disconnection(wpa_s);
2014 		return NULL;
2015 	}
2016 
2017 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
2018 				      "This interface is not connected");
2019 }
2020 
2021 
2022 /**
2023  * wpas_dbus_new_iface_add_network - Add a new configured network
2024  * @message: Pointer to incoming dbus message
2025  * @wpa_s: wpa_supplicant structure for a network interface
2026  * Returns: A dbus message containing the object path of the new network
2027  *
2028  * Handler function for "AddNetwork" method call of a network interface.
2029  */
wpas_dbus_handler_add_network(DBusMessage * message,struct wpa_supplicant * wpa_s)2030 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
2031 					    struct wpa_supplicant *wpa_s)
2032 {
2033 	DBusMessage *reply = NULL;
2034 	DBusMessageIter	iter;
2035 	struct wpa_ssid *ssid = NULL;
2036 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
2037 	DBusError error;
2038 
2039 	dbus_message_iter_init(message, &iter);
2040 
2041 	if (wpa_s->dbus_new_path)
2042 		ssid = wpa_supplicant_add_network(wpa_s);
2043 	if (ssid == NULL) {
2044 		wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
2045 			   __func__);
2046 		reply = wpas_dbus_error_unknown_error(
2047 			message,
2048 			"wpa_supplicant could not add a network on this interface.");
2049 		goto err;
2050 	}
2051 
2052 	dbus_error_init(&error);
2053 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
2054 		wpa_printf(MSG_DEBUG,
2055 			   "%s[dbus]: control interface couldn't set network properties",
2056 			   __func__);
2057 		reply = wpas_dbus_reply_new_from_error(message, &error,
2058 						       DBUS_ERROR_INVALID_ARGS,
2059 						       "Failed to add network");
2060 		dbus_error_free(&error);
2061 		goto err;
2062 	}
2063 
2064 	/* Construct the object path for this network. */
2065 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
2066 		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
2067 		    wpa_s->dbus_new_path, ssid->id);
2068 
2069 	reply = dbus_message_new_method_return(message);
2070 	if (reply == NULL) {
2071 		reply = wpas_dbus_error_no_memory(message);
2072 		goto err;
2073 	}
2074 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
2075 				      DBUS_TYPE_INVALID)) {
2076 		dbus_message_unref(reply);
2077 		reply = wpas_dbus_error_no_memory(message);
2078 		goto err;
2079 	}
2080 
2081 	return reply;
2082 
2083 err:
2084 	if (ssid) {
2085 		wpas_notify_network_removed(wpa_s, ssid);
2086 		wpa_config_remove_network(wpa_s->conf, ssid->id);
2087 	}
2088 	return reply;
2089 }
2090 
2091 
2092 /**
2093  * wpas_dbus_handler_reassociate - Reassociate
2094  * @message: Pointer to incoming dbus message
2095  * @wpa_s: wpa_supplicant structure for a network interface
2096  * Returns: InterfaceDisabled DBus error message if disabled
2097  * or NULL otherwise.
2098  *
2099  * Handler function for "Reassociate" method call of network interface.
2100  */
wpas_dbus_handler_reassociate(DBusMessage * message,struct wpa_supplicant * wpa_s)2101 DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
2102 					    struct wpa_supplicant *wpa_s)
2103 {
2104 	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
2105 		wpas_request_connection(wpa_s);
2106 		return NULL;
2107 	}
2108 
2109 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
2110 				      "This interface is disabled");
2111 }
2112 
2113 
2114 /**
2115  * wpas_dbus_handler_expect_disconnect - ExpectDisconnect
2116  * @message: Pointer to incoming dbus message
2117  * @global: %wpa_supplicant global data structure
2118  * Returns: NULL
2119  *
2120  * Handler function for notifying system there will be a expected disconnect.
2121  * This will prevent wpa_supplicant from adding the BSSID to the ignore list
2122  * upon next disconnect.
2123  */
wpas_dbus_handler_expect_disconnect(DBusMessage * message,struct wpa_global * global)2124 DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
2125 						  struct wpa_global *global)
2126 {
2127 	struct wpa_supplicant *wpa_s = global->ifaces;
2128 
2129 	for (; wpa_s; wpa_s = wpa_s->next)
2130 		if (wpa_s->wpa_state >= WPA_ASSOCIATED)
2131 			wpa_s->own_disconnect_req = 1;
2132 	return NULL;
2133 }
2134 
2135 
2136 /**
2137  * wpas_dbus_handler_reattach - Reattach to current AP
2138  * @message: Pointer to incoming dbus message
2139  * @wpa_s: wpa_supplicant structure for a network interface
2140  * Returns: NotConnected DBus error message if not connected
2141  * or NULL otherwise.
2142  *
2143  * Handler function for "Reattach" method call of network interface.
2144  */
wpas_dbus_handler_reattach(DBusMessage * message,struct wpa_supplicant * wpa_s)2145 DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
2146 					 struct wpa_supplicant *wpa_s)
2147 {
2148 	if (wpa_s->current_ssid != NULL) {
2149 		wpa_s->reattach = 1;
2150 		wpas_request_connection(wpa_s);
2151 		return NULL;
2152 	}
2153 
2154 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
2155 				      "This interface is not connected");
2156 }
2157 
2158 
2159 /**
2160  * wpas_dbus_handler_reconnect - Reconnect if disconnected
2161  * @message: Pointer to incoming dbus message
2162  * @wpa_s: wpa_supplicant structure for a network interface
2163  * Returns: InterfaceDisabled DBus error message if disabled
2164  * or NULL otherwise.
2165  *
2166  * Handler function for "Reconnect" method call of network interface.
2167  */
wpas_dbus_handler_reconnect(DBusMessage * message,struct wpa_supplicant * wpa_s)2168 DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
2169 		struct wpa_supplicant *wpa_s)
2170 {
2171 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
2172 		return dbus_message_new_error(message,
2173 					      WPAS_DBUS_ERROR_IFACE_DISABLED,
2174 					      "This interface is disabled");
2175 	}
2176 
2177 	if (wpa_s->disconnected)
2178 		wpas_request_connection(wpa_s);
2179 	return NULL;
2180 }
2181 
2182 
2183 /**
2184  * wpas_dbus_handler_remove_network - Remove a configured network
2185  * @message: Pointer to incoming dbus message
2186  * @wpa_s: wpa_supplicant structure for a network interface
2187  * Returns: NULL on success or dbus error on failure
2188  *
2189  * Handler function for "RemoveNetwork" method call of a network interface.
2190  */
wpas_dbus_handler_remove_network(DBusMessage * message,struct wpa_supplicant * wpa_s)2191 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
2192 					       struct wpa_supplicant *wpa_s)
2193 {
2194 	DBusMessage *reply = NULL;
2195 	const char *op;
2196 	char *iface, *net_id;
2197 	int id;
2198 	int result;
2199 
2200 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
2201 			      DBUS_TYPE_INVALID);
2202 
2203 	/* Extract the network ID and ensure the network */
2204 	/* is actually a child of this interface */
2205 	iface = wpas_dbus_new_decompose_object_path(op,
2206 						    WPAS_DBUS_NEW_NETWORKS_PART,
2207 						    &net_id);
2208 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
2209 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
2210 		reply = wpas_dbus_error_invalid_args(message, op);
2211 		goto out;
2212 	}
2213 
2214 	errno = 0;
2215 	id = strtoul(net_id, NULL, 10);
2216 	if (errno != 0) {
2217 		reply = wpas_dbus_error_invalid_args(message, op);
2218 		goto out;
2219 	}
2220 
2221 	result = wpa_supplicant_remove_network(wpa_s, id);
2222 	if (result == -1) {
2223 		reply = wpas_dbus_error_network_unknown(message);
2224 		goto out;
2225 	}
2226 	if (result == -2) {
2227 		wpa_printf(MSG_ERROR,
2228 			   "%s[dbus]: error occurred when removing network %d",
2229 			   __func__, id);
2230 		reply = wpas_dbus_error_unknown_error(
2231 			message,
2232 			"error removing the specified network on is interface.");
2233 		goto out;
2234 	}
2235 
2236 out:
2237 	os_free(iface);
2238 	return reply;
2239 }
2240 
2241 
2242 /**
2243  * wpas_dbus_handler_remove_all_networks - Remove all configured networks
2244  * @message: Pointer to incoming dbus message
2245  * @wpa_s: wpa_supplicant structure for a network interface
2246  * Returns: NULL on success or dbus error on failure
2247  *
2248  * Handler function for "RemoveAllNetworks" method call of a network interface.
2249  */
wpas_dbus_handler_remove_all_networks(DBusMessage * message,struct wpa_supplicant * wpa_s)2250 DBusMessage * wpas_dbus_handler_remove_all_networks(
2251 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2252 {
2253 	/* NB: could check for failure and return an error */
2254 	wpa_supplicant_remove_all_networks(wpa_s);
2255 	return NULL;
2256 }
2257 
2258 
2259 /**
2260  * wpas_dbus_handler_select_network - Attempt association with a network
2261  * @message: Pointer to incoming dbus message
2262  * @wpa_s: wpa_supplicant structure for a network interface
2263  * Returns: NULL on success or dbus error on failure
2264  *
2265  * Handler function for "SelectNetwork" method call of network interface.
2266  */
wpas_dbus_handler_select_network(DBusMessage * message,struct wpa_supplicant * wpa_s)2267 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
2268 					       struct wpa_supplicant *wpa_s)
2269 {
2270 	DBusMessage *reply = NULL;
2271 	const char *op;
2272 	char *iface, *net_id;
2273 	int id;
2274 	struct wpa_ssid *ssid;
2275 
2276 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
2277 			      DBUS_TYPE_INVALID);
2278 
2279 	/* Extract the network ID and ensure the network */
2280 	/* is actually a child of this interface */
2281 	iface = wpas_dbus_new_decompose_object_path(op,
2282 						    WPAS_DBUS_NEW_NETWORKS_PART,
2283 						    &net_id);
2284 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
2285 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
2286 		reply = wpas_dbus_error_invalid_args(message, op);
2287 		goto out;
2288 	}
2289 
2290 	errno = 0;
2291 	id = strtoul(net_id, NULL, 10);
2292 	if (errno != 0) {
2293 		reply = wpas_dbus_error_invalid_args(message, op);
2294 		goto out;
2295 	}
2296 
2297 	ssid = wpa_config_get_network(wpa_s->conf, id);
2298 	if (ssid == NULL) {
2299 		reply = wpas_dbus_error_network_unknown(message);
2300 		goto out;
2301 	}
2302 
2303 	/* Finally, associate with the network */
2304 	wpa_supplicant_select_network(wpa_s, ssid);
2305 
2306 out:
2307 	os_free(iface);
2308 	return reply;
2309 }
2310 
2311 
2312 /**
2313  * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
2314  * @message: Pointer to incoming dbus message
2315  * @wpa_s: wpa_supplicant structure for a network interface
2316  * Returns: NULL on success or dbus error on failure
2317  *
2318  * Handler function for "NetworkReply" method call of network interface.
2319  */
wpas_dbus_handler_network_reply(DBusMessage * message,struct wpa_supplicant * wpa_s)2320 DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
2321 					      struct wpa_supplicant *wpa_s)
2322 {
2323 #ifdef IEEE8021X_EAPOL
2324 	DBusMessage *reply = NULL;
2325 	const char *op, *field, *value;
2326 	char *iface, *net_id;
2327 	int id;
2328 	struct wpa_ssid *ssid;
2329 
2330 	if (!dbus_message_get_args(message, NULL,
2331 				   DBUS_TYPE_OBJECT_PATH, &op,
2332 				   DBUS_TYPE_STRING, &field,
2333 				   DBUS_TYPE_STRING, &value,
2334 				   DBUS_TYPE_INVALID))
2335 		return wpas_dbus_error_invalid_args(message, NULL);
2336 
2337 	/* Extract the network ID and ensure the network */
2338 	/* is actually a child of this interface */
2339 	iface = wpas_dbus_new_decompose_object_path(op,
2340 						    WPAS_DBUS_NEW_NETWORKS_PART,
2341 						    &net_id);
2342 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
2343 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
2344 		reply = wpas_dbus_error_invalid_args(message, op);
2345 		goto out;
2346 	}
2347 
2348 	errno = 0;
2349 	id = strtoul(net_id, NULL, 10);
2350 	if (errno != 0) {
2351 		reply = wpas_dbus_error_invalid_args(message, net_id);
2352 		goto out;
2353 	}
2354 
2355 	ssid = wpa_config_get_network(wpa_s->conf, id);
2356 	if (ssid == NULL) {
2357 		reply = wpas_dbus_error_network_unknown(message);
2358 		goto out;
2359 	}
2360 
2361 	if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
2362 						      field, value) < 0)
2363 		reply = wpas_dbus_error_invalid_args(message, field);
2364 	else {
2365 		/* Tell EAP to retry immediately */
2366 		eapol_sm_notify_ctrl_response(wpa_s->eapol);
2367 	}
2368 
2369 out:
2370 	os_free(iface);
2371 	return reply;
2372 #else /* IEEE8021X_EAPOL */
2373 	wpa_printf(MSG_DEBUG, "dbus: 802.1X not included");
2374 	return wpas_dbus_error_unknown_error(message, "802.1X not included");
2375 #endif /* IEEE8021X_EAPOL */
2376 }
2377 
2378 
2379 /**
2380  * wpas_dbus_handler_roam - Initiate a roam to another BSS within the ESS
2381  * @message: Pointer to incoming dbus message
2382  * @wpa_s: wpa_supplicant structure for a network interface
2383  * Returns: NULL on success or dbus error on failure
2384  *
2385  * Handler function for "Roam" method call of network interface.
2386  */
wpas_dbus_handler_roam(DBusMessage * message,struct wpa_supplicant * wpa_s)2387 DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
2388 				     struct wpa_supplicant *wpa_s)
2389 {
2390 #ifdef CONFIG_NO_SCAN_PROCESSING
2391 	return wpas_dbus_error_unknown_error(message,
2392 					     "scan processing not included");
2393 #else /* CONFIG_NO_SCAN_PROCESSING */
2394 	u8 bssid[ETH_ALEN];
2395 	struct wpa_bss *bss;
2396 	struct wpa_ssid *ssid = wpa_s->current_ssid;
2397 	char *addr;
2398 	struct wpa_radio_work *already_connecting;
2399 
2400 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &addr,
2401 				   DBUS_TYPE_INVALID))
2402 		return wpas_dbus_error_invalid_args(message, NULL);
2403 
2404 	if (hwaddr_aton(addr, bssid))
2405 		return wpas_dbus_error_invalid_args(
2406 			message, "Invalid hardware address format");
2407 
2408 	wpa_printf(MSG_DEBUG, "dbus: Roam " MACSTR, MAC2STR(bssid));
2409 
2410 	if (!ssid)
2411 		return dbus_message_new_error(
2412 			message, WPAS_DBUS_ERROR_NOT_CONNECTED,
2413 			"This interface is not connected");
2414 
2415 	bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
2416 	if (!bss) {
2417 		wpa_printf(MSG_DEBUG, "dbus: Roam: Target BSS not found");
2418 		return wpas_dbus_error_invalid_args(
2419 			message, "Target BSS not found");
2420 	}
2421 
2422 	already_connecting = radio_work_pending(wpa_s, "sme-connect");
2423 	wpa_s->reassociate = 1;
2424 	wpa_supplicant_connect(wpa_s, bss, ssid);
2425 
2426 	/*
2427 	 * Indicate that an explicitly requested roam is in progress so scan
2428 	 * results that come in before the 'sme-connect' radio work gets
2429 	 * executed do not override the original connection attempt.
2430 	 */
2431 	if (!already_connecting && radio_work_pending(wpa_s, "sme-connect"))
2432 		wpa_s->roam_in_progress = true;
2433 
2434 	return NULL;
2435 #endif /* CONFIG_NO_SCAN_PROCESSING */
2436 }
2437 
2438 #ifndef CONFIG_NO_CONFIG_BLOBS
2439 
2440 /**
2441  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
2442  * @message: Pointer to incoming dbus message
2443  * @wpa_s: %wpa_supplicant data structure
2444  * Returns: A dbus message containing an error on failure or NULL on success
2445  *
2446  * Asks wpa_supplicant to internally store a binary blobs.
2447  */
wpas_dbus_handler_add_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)2448 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
2449 					 struct wpa_supplicant *wpa_s)
2450 {
2451 	DBusMessage *reply = NULL;
2452 	DBusMessageIter	iter, array_iter;
2453 
2454 	char *blob_name;
2455 	u8 *blob_data;
2456 	int blob_len;
2457 	struct wpa_config_blob *blob = NULL;
2458 
2459 	dbus_message_iter_init(message, &iter);
2460 	dbus_message_iter_get_basic(&iter, &blob_name);
2461 
2462 	if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
2463 		return dbus_message_new_error(message,
2464 					      WPAS_DBUS_ERROR_BLOB_EXISTS,
2465 					      NULL);
2466 	}
2467 
2468 	dbus_message_iter_next(&iter);
2469 	dbus_message_iter_recurse(&iter, &array_iter);
2470 
2471 	dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
2472 
2473 	blob = os_zalloc(sizeof(*blob));
2474 	if (!blob) {
2475 		reply = wpas_dbus_error_no_memory(message);
2476 		goto err;
2477 	}
2478 
2479 	blob->data = os_memdup(blob_data, blob_len);
2480 	blob->name = os_strdup(blob_name);
2481 	if (!blob->data || !blob->name) {
2482 		reply = wpas_dbus_error_no_memory(message);
2483 		goto err;
2484 	}
2485 	blob->len = blob_len;
2486 
2487 	wpa_config_set_blob(wpa_s->conf, blob);
2488 	wpas_notify_blob_added(wpa_s, blob->name);
2489 
2490 	return reply;
2491 
2492 err:
2493 	if (blob) {
2494 		os_free(blob->name);
2495 		os_free(blob->data);
2496 		os_free(blob);
2497 	}
2498 	return reply;
2499 }
2500 
2501 
2502 /**
2503  * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
2504  * @message: Pointer to incoming dbus message
2505  * @wpa_s: %wpa_supplicant data structure
2506  * Returns: A dbus message containing array of bytes (blob)
2507  *
2508  * Gets one wpa_supplicant's binary blobs.
2509  */
wpas_dbus_handler_get_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)2510 DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
2511 					 struct wpa_supplicant *wpa_s)
2512 {
2513 	DBusMessage *reply = NULL;
2514 	DBusMessageIter	iter, array_iter;
2515 
2516 	char *blob_name;
2517 	const struct wpa_config_blob *blob;
2518 
2519 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
2520 			      DBUS_TYPE_INVALID);
2521 
2522 	blob = wpa_config_get_blob(wpa_s->conf, blob_name);
2523 	if (!blob) {
2524 		return dbus_message_new_error(message,
2525 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
2526 					      "Blob id not set");
2527 	}
2528 
2529 	reply = dbus_message_new_method_return(message);
2530 	if (!reply)
2531 		return wpas_dbus_error_no_memory(message);
2532 
2533 	dbus_message_iter_init_append(reply, &iter);
2534 
2535 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
2536 					      DBUS_TYPE_BYTE_AS_STRING,
2537 					      &array_iter) ||
2538 	    !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
2539 						  &(blob->data), blob->len) ||
2540 	    !dbus_message_iter_close_container(&iter, &array_iter)) {
2541 		dbus_message_unref(reply);
2542 		reply = wpas_dbus_error_no_memory(message);
2543 	}
2544 
2545 	return reply;
2546 }
2547 
2548 
2549 /**
2550  * wpas_remove_handler_remove_blob - Remove named binary blob
2551  * @message: Pointer to incoming dbus message
2552  * @wpa_s: %wpa_supplicant data structure
2553  * Returns: NULL on success or dbus error
2554  *
2555  * Asks wpa_supplicant to internally remove a binary blobs.
2556  */
wpas_dbus_handler_remove_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)2557 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
2558 					    struct wpa_supplicant *wpa_s)
2559 {
2560 	DBusMessage *reply = NULL;
2561 	char *blob_name;
2562 
2563 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
2564 			      DBUS_TYPE_INVALID);
2565 
2566 	if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
2567 		return dbus_message_new_error(message,
2568 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
2569 					      "Blob id not set");
2570 	}
2571 	wpas_notify_blob_removed(wpa_s, blob_name);
2572 
2573 	return reply;
2574 
2575 }
2576 
2577 #endif /* CONFIG_NO_CONFIG_BLOBS */
2578 
2579 
2580 /*
2581  * wpas_dbus_handler_flush_bss - Flush the BSS cache
2582  * @message: Pointer to incoming dbus message
2583  * @wpa_s: wpa_supplicant structure for a network interface
2584  * Returns: NULL
2585  *
2586  * Handler function for "FlushBSS" method call of network interface.
2587  */
wpas_dbus_handler_flush_bss(DBusMessage * message,struct wpa_supplicant * wpa_s)2588 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
2589 					  struct wpa_supplicant *wpa_s)
2590 {
2591 	dbus_uint32_t age;
2592 
2593 	dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
2594 			      DBUS_TYPE_INVALID);
2595 
2596 	if (age == 0)
2597 		wpa_bss_flush(wpa_s);
2598 	else
2599 		wpa_bss_flush_by_age(wpa_s, age);
2600 
2601 	return NULL;
2602 }
2603 
2604 
2605 #ifdef CONFIG_AUTOSCAN
2606 /**
2607  * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
2608  * @message: Pointer to incoming dbus message
2609  * @wpa_s: wpa_supplicant structure for a network interface
2610  * Returns: NULL
2611  *
2612  * Handler function for "AutoScan" method call of network interface.
2613  */
wpas_dbus_handler_autoscan(DBusMessage * message,struct wpa_supplicant * wpa_s)2614 DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
2615 					 struct wpa_supplicant *wpa_s)
2616 {
2617 	DBusMessage *reply = NULL;
2618 	enum wpa_states state = wpa_s->wpa_state;
2619 	char *arg;
2620 
2621 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
2622 			      DBUS_TYPE_INVALID);
2623 
2624 	if (arg != NULL && os_strlen(arg) > 0) {
2625 		char *tmp;
2626 
2627 		tmp = os_strdup(arg);
2628 		if (tmp == NULL) {
2629 			reply = wpas_dbus_error_no_memory(message);
2630 		} else {
2631 			os_free(wpa_s->conf->autoscan);
2632 			wpa_s->conf->autoscan = tmp;
2633 			if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
2634 				autoscan_init(wpa_s, 1);
2635 			else if (state == WPA_SCANNING)
2636 				wpa_supplicant_reinit_autoscan(wpa_s);
2637 		}
2638 	} else if (arg != NULL && os_strlen(arg) == 0) {
2639 		os_free(wpa_s->conf->autoscan);
2640 		wpa_s->conf->autoscan = NULL;
2641 		autoscan_deinit(wpa_s);
2642 	} else
2643 		reply = dbus_message_new_error(message,
2644 					       DBUS_ERROR_INVALID_ARGS,
2645 					       NULL);
2646 
2647 	return reply;
2648 }
2649 #endif /* CONFIG_AUTOSCAN */
2650 
2651 
2652 /*
2653  * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
2654  * @message: Pointer to incoming dbus message
2655  * @wpa_s: wpa_supplicant structure for a network interface
2656  * Returns: NULL
2657  *
2658  * Handler function for "EAPLogoff" method call of network interface.
2659  */
wpas_dbus_handler_eap_logoff(DBusMessage * message,struct wpa_supplicant * wpa_s)2660 DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
2661 					   struct wpa_supplicant *wpa_s)
2662 {
2663 	eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
2664 	return NULL;
2665 }
2666 
2667 
2668 /*
2669  * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
2670  * @message: Pointer to incoming dbus message
2671  * @wpa_s: wpa_supplicant structure for a network interface
2672  * Returns: NULL
2673  *
2674  * Handler function for "EAPLogin" method call of network interface.
2675  */
wpas_dbus_handler_eap_logon(DBusMessage * message,struct wpa_supplicant * wpa_s)2676 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
2677 					  struct wpa_supplicant *wpa_s)
2678 {
2679 	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
2680 	return NULL;
2681 }
2682 
2683 
2684 #ifdef CONFIG_TDLS
2685 
get_peer_hwaddr_helper(DBusMessage * message,const char * func_name,u8 * peer_address,DBusMessage ** error)2686 static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
2687 				  u8 *peer_address, DBusMessage **error)
2688 {
2689 	const char *peer_string;
2690 
2691 	*error = NULL;
2692 
2693 	if (!dbus_message_get_args(message, NULL,
2694 				   DBUS_TYPE_STRING, &peer_string,
2695 				   DBUS_TYPE_INVALID)) {
2696 		*error = wpas_dbus_error_invalid_args(message, NULL);
2697 		return -1;
2698 	}
2699 
2700 	if (hwaddr_aton(peer_string, peer_address)) {
2701 		wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
2702 			   func_name, peer_string);
2703 		*error = wpas_dbus_error_invalid_args(
2704 			message, "Invalid hardware address format");
2705 		return -1;
2706 	}
2707 
2708 	return 0;
2709 }
2710 
2711 
2712 /*
2713  * wpas_dbus_handler_tdls_discover - Discover TDLS peer
2714  * @message: Pointer to incoming dbus message
2715  * @wpa_s: wpa_supplicant structure for a network interface
2716  * Returns: NULL indicating success or DBus error message on failure
2717  *
2718  * Handler function for "TDLSDiscover" method call of network interface.
2719  */
wpas_dbus_handler_tdls_discover(DBusMessage * message,struct wpa_supplicant * wpa_s)2720 DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
2721 					      struct wpa_supplicant *wpa_s)
2722 {
2723 	u8 peer[ETH_ALEN];
2724 	DBusMessage *error_reply;
2725 	int ret;
2726 
2727 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2728 		return error_reply;
2729 
2730 	wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
2731 
2732 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2733 		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
2734 	else
2735 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
2736 
2737 	if (ret) {
2738 		return wpas_dbus_error_unknown_error(
2739 			message, "error performing TDLS discovery");
2740 	}
2741 
2742 	return NULL;
2743 }
2744 
2745 
2746 /*
2747  * wpas_dbus_handler_tdls_setup - Setup TDLS session
2748  * @message: Pointer to incoming dbus message
2749  * @wpa_s: wpa_supplicant structure for a network interface
2750  * Returns: NULL indicating success or DBus error message on failure
2751  *
2752  * Handler function for "TDLSSetup" method call of network interface.
2753  */
wpas_dbus_handler_tdls_setup(DBusMessage * message,struct wpa_supplicant * wpa_s)2754 DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
2755 					   struct wpa_supplicant *wpa_s)
2756 {
2757 	u8 peer[ETH_ALEN];
2758 	DBusMessage *error_reply;
2759 	int ret;
2760 
2761 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2762 		return error_reply;
2763 
2764 	wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
2765 
2766 	wpa_tdls_remove(wpa_s->wpa, peer);
2767 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2768 		ret = wpa_tdls_start(wpa_s->wpa, peer);
2769 	else
2770 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2771 
2772 	if (ret) {
2773 		return wpas_dbus_error_unknown_error(
2774 			message, "error performing TDLS setup");
2775 	}
2776 
2777 	return NULL;
2778 }
2779 
2780 
2781 /*
2782  * wpas_dbus_handler_tdls_status - Return TDLS session status
2783  * @message: Pointer to incoming dbus message
2784  * @wpa_s: wpa_supplicant structure for a network interface
2785  * Returns: A string representing the state of the link to this TDLS peer
2786  *
2787  * Handler function for "TDLSStatus" method call of network interface.
2788  */
wpas_dbus_handler_tdls_status(DBusMessage * message,struct wpa_supplicant * wpa_s)2789 DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
2790 					    struct wpa_supplicant *wpa_s)
2791 {
2792 	u8 peer[ETH_ALEN];
2793 	DBusMessage *reply;
2794 	const char *tdls_status;
2795 
2796 	if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
2797 		return reply;
2798 
2799 	wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
2800 
2801 	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
2802 
2803 	reply = dbus_message_new_method_return(message);
2804 	dbus_message_append_args(reply, DBUS_TYPE_STRING,
2805 				 &tdls_status, DBUS_TYPE_INVALID);
2806 	return reply;
2807 }
2808 
2809 
2810 /*
2811  * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
2812  * @message: Pointer to incoming dbus message
2813  * @wpa_s: wpa_supplicant structure for a network interface
2814  * Returns: NULL indicating success or DBus error message on failure
2815  *
2816  * Handler function for "TDLSTeardown" method call of network interface.
2817  */
wpas_dbus_handler_tdls_teardown(DBusMessage * message,struct wpa_supplicant * wpa_s)2818 DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
2819 					      struct wpa_supplicant *wpa_s)
2820 {
2821 	u8 peer[ETH_ALEN];
2822 	DBusMessage *error_reply;
2823 	int ret;
2824 
2825 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2826 		return error_reply;
2827 
2828 	wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
2829 
2830 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2831 		ret = wpa_tdls_teardown_link(
2832 			wpa_s->wpa, peer,
2833 			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
2834 	else
2835 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
2836 
2837 	if (ret) {
2838 		return wpas_dbus_error_unknown_error(
2839 			message, "error performing TDLS teardown");
2840 	}
2841 
2842 	return NULL;
2843 }
2844 
2845 /*
2846  * wpas_dbus_handler_tdls_channel_switch - Enable channel switching with TDLS peer
2847  * @message: Pointer to incoming dbus message
2848  * @wpa_s: wpa_supplicant structure for a network interface
2849  * Returns: NULL indicating success or DBus error message on failure
2850  *
2851  * Handler function for "TDLSChannelSwitch" method call of network interface.
2852  */
2853 DBusMessage *
wpas_dbus_handler_tdls_channel_switch(DBusMessage * message,struct wpa_supplicant * wpa_s)2854 wpas_dbus_handler_tdls_channel_switch(DBusMessage *message,
2855 				      struct wpa_supplicant *wpa_s)
2856 {
2857 	DBusMessageIter	iter, iter_dict;
2858 	struct wpa_dbus_dict_entry entry;
2859 	u8 peer[ETH_ALEN];
2860 	struct hostapd_freq_params freq_params;
2861 	u8 oper_class = 0;
2862 	int ret;
2863 	int is_peer_present = 0;
2864 
2865 	if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
2866 		wpa_printf(MSG_INFO,
2867 			   "tdls_chanswitch: Only supported with external setup");
2868 		return wpas_dbus_error_unknown_error(message, "TDLS is not using external setup");
2869 	}
2870 
2871 	os_memset(&freq_params, 0, sizeof(freq_params));
2872 
2873 	dbus_message_iter_init(message, &iter);
2874 
2875 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2876 		return wpas_dbus_error_invalid_args(message, NULL);
2877 
2878 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2879 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2880 			return wpas_dbus_error_invalid_args(message, NULL);
2881 
2882 		if (os_strcmp(entry.key, "PeerAddress") == 0 &&
2883 		    entry.type == DBUS_TYPE_STRING) {
2884 			if (hwaddr_aton(entry.str_value, peer)) {
2885 				wpa_printf(MSG_DEBUG,
2886 					   "tdls_chanswitch: Invalid address '%s'",
2887 					   entry.str_value);
2888 				wpa_dbus_dict_entry_clear(&entry);
2889 				return wpas_dbus_error_invalid_args(message,
2890 								    NULL);
2891 			}
2892 
2893 			is_peer_present = 1;
2894 		} else if (os_strcmp(entry.key, "OperClass") == 0 &&
2895 			   entry.type == DBUS_TYPE_BYTE) {
2896 			oper_class = entry.byte_value;
2897 		} else if (os_strcmp(entry.key, "Frequency") == 0 &&
2898 			   entry.type == DBUS_TYPE_UINT32) {
2899 			freq_params.freq = entry.uint32_value;
2900 		} else if (os_strcmp(entry.key, "SecChannelOffset") == 0 &&
2901 			   entry.type == DBUS_TYPE_UINT32) {
2902 			freq_params.sec_channel_offset = entry.uint32_value;
2903 		} else if (os_strcmp(entry.key, "CenterFrequency1") == 0 &&
2904 			   entry.type == DBUS_TYPE_UINT32) {
2905 			freq_params.center_freq1 = entry.uint32_value;
2906 		} else if (os_strcmp(entry.key, "CenterFrequency2") == 0 &&
2907 			   entry.type == DBUS_TYPE_UINT32) {
2908 			freq_params.center_freq2 = entry.uint32_value;
2909 		} else if (os_strcmp(entry.key, "Bandwidth") == 0 &&
2910 			   entry.type == DBUS_TYPE_UINT32) {
2911 			freq_params.bandwidth = entry.uint32_value;
2912 		} else if (os_strcmp(entry.key, "HT") == 0 &&
2913 			   entry.type == DBUS_TYPE_BOOLEAN) {
2914 			freq_params.ht_enabled = entry.bool_value;
2915 		} else if (os_strcmp(entry.key, "VHT") == 0 &&
2916 			   entry.type == DBUS_TYPE_BOOLEAN) {
2917 			freq_params.vht_enabled = entry.bool_value;
2918 		} else {
2919 			wpa_dbus_dict_entry_clear(&entry);
2920 			return wpas_dbus_error_invalid_args(message, NULL);
2921 		}
2922 
2923 		wpa_dbus_dict_entry_clear(&entry);
2924 	}
2925 
2926 	if (oper_class == 0) {
2927 		wpa_printf(MSG_INFO,
2928 			   "tdls_chanswitch: Invalid op class provided");
2929 		return wpas_dbus_error_invalid_args(
2930 			message, "Invalid op class provided");
2931 	}
2932 
2933 	if (freq_params.freq == 0) {
2934 		wpa_printf(MSG_INFO,
2935 			   "tdls_chanswitch: Invalid freq provided");
2936 		return wpas_dbus_error_invalid_args(message,
2937 						    "Invalid freq provided");
2938 	}
2939 
2940 	if (is_peer_present == 0) {
2941 		wpa_printf(MSG_DEBUG,
2942 			   "tdls_chanswitch: peer address not provided");
2943 		return wpas_dbus_error_invalid_args(
2944 			message, "peer address not provided");
2945 	}
2946 
2947 	wpa_printf(MSG_DEBUG, "dbus: TDLS_CHAN_SWITCH " MACSTR
2948 		   " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
2949 		   MAC2STR(peer), oper_class, freq_params.freq,
2950 		   freq_params.center_freq1, freq_params.center_freq2,
2951 		   freq_params.bandwidth, freq_params.sec_channel_offset,
2952 		   freq_params.ht_enabled ? " HT" : "",
2953 		   freq_params.vht_enabled ? " VHT" : "");
2954 
2955 	ret = wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
2956 					  &freq_params);
2957 	if (ret)
2958 		return wpas_dbus_error_unknown_error(
2959 			message, "error processing TDLS channel switch");
2960 
2961 	return NULL;
2962 }
2963 
2964 /*
2965  * wpas_dbus_handler_tdls_cancel_channel_switch - Disable channel switching with TDLS peer
2966  * @message: Pointer to incoming dbus message
2967  * @wpa_s: wpa_supplicant structure for a network interface
2968  * Returns: NULL indicating success or DBus error message on failure
2969  *
2970  * Handler function for "TDLSCancelChannelSwitch" method call of network
2971  * interface.
2972  */
2973 DBusMessage *
wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage * message,struct wpa_supplicant * wpa_s)2974 wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message,
2975 					     struct wpa_supplicant *wpa_s)
2976 {
2977 	u8 peer[ETH_ALEN];
2978 	DBusMessage *error_reply;
2979 	int ret;
2980 
2981 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2982 		return error_reply;
2983 
2984 	wpa_printf(MSG_DEBUG, "dbus: TDLS_CANCEL_CHAN_SWITCH " MACSTR,
2985 		   MAC2STR(peer));
2986 
2987 	ret = wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
2988 	if (ret)
2989 		return wpas_dbus_error_unknown_error(
2990 			message, "error canceling TDLS channel switch");
2991 
2992 	return NULL;
2993 }
2994 
2995 #endif /* CONFIG_TDLS */
2996 
2997 
2998 #ifndef CONFIG_NO_CONFIG_WRITE
2999 /**
3000  * wpas_dbus_handler_save_config - Save configuration to configuration file
3001  * @message: Pointer to incoming dbus message
3002  * @wpa_s: wpa_supplicant structure for a network interface
3003  * Returns: NULL on Success, Otherwise error message
3004  *
3005  * Handler function for "SaveConfig" method call of network interface.
3006  */
wpas_dbus_handler_save_config(DBusMessage * message,struct wpa_supplicant * wpa_s)3007 DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
3008 					    struct wpa_supplicant *wpa_s)
3009 {
3010 	int ret;
3011 
3012 	if (!wpa_s->conf->update_config) {
3013 		return wpas_dbus_error_unknown_error(
3014 			message,
3015 			"Not allowed to update configuration (update_config=0)");
3016 	}
3017 
3018 	ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
3019 	if (ret)
3020 		return wpas_dbus_error_unknown_error(
3021 			message, "Failed to update configuration");
3022 	return NULL;
3023 }
3024 #endif /* CONFIG_NO_CONFIG_WRITE */
3025 
3026 
3027 /**
3028  * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
3029  * @message: Pointer to incoming dbus message
3030  * @wpa_s: %wpa_supplicant data structure
3031  * Returns: A dbus message containing an error on failure or NULL on success
3032  *
3033  * Sets the PKCS #11 engine and module path.
3034  */
wpas_dbus_handler_set_pkcs11_engine_and_module_path(DBusMessage * message,struct wpa_supplicant * wpa_s)3035 DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
3036 	DBusMessage *message, struct wpa_supplicant *wpa_s)
3037 {
3038 	DBusMessageIter iter;
3039 	char *value = NULL;
3040 	char *pkcs11_engine_path = NULL;
3041 	char *pkcs11_module_path = NULL;
3042 
3043 	dbus_message_iter_init(message, &iter);
3044 	dbus_message_iter_get_basic(&iter, &value);
3045 	if (value == NULL) {
3046 		return dbus_message_new_error(
3047 			message, DBUS_ERROR_INVALID_ARGS,
3048 			"Invalid pkcs11_engine_path argument");
3049 	}
3050 	/* Empty path defaults to NULL */
3051 	if (os_strlen(value))
3052 		pkcs11_engine_path = value;
3053 
3054 	dbus_message_iter_next(&iter);
3055 	dbus_message_iter_get_basic(&iter, &value);
3056 	if (value == NULL) {
3057 		os_free(pkcs11_engine_path);
3058 		return dbus_message_new_error(
3059 			message, DBUS_ERROR_INVALID_ARGS,
3060 			"Invalid pkcs11_module_path argument");
3061 	}
3062 	/* Empty path defaults to NULL */
3063 	if (os_strlen(value))
3064 		pkcs11_module_path = value;
3065 
3066 	if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
3067 						   pkcs11_module_path))
3068 		return dbus_message_new_error(
3069 			message, DBUS_ERROR_FAILED,
3070 			"Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
3071 
3072 	if (wpa_s->dbus_new_path) {
3073 		wpa_dbus_mark_property_changed(
3074 			wpa_s->global->dbus, wpa_s->dbus_new_path,
3075 			WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
3076 		wpa_dbus_mark_property_changed(
3077 			wpa_s->global->dbus, wpa_s->dbus_new_path,
3078 			WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
3079 	}
3080 
3081 	return NULL;
3082 }
3083 
3084 
3085 /**
3086  * wpas_dbus_getter_capabilities - Return interface capabilities
3087  * @iter: Pointer to incoming dbus message iter
3088  * @error: Location to store error on failure
3089  * @user_data: Function specific data
3090  * Returns: TRUE on success, FALSE on failure
3091  *
3092  * Getter for "Capabilities" property of an interface.
3093  */
wpas_dbus_getter_capabilities(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3094 dbus_bool_t wpas_dbus_getter_capabilities(
3095 	const struct wpa_dbus_property_desc *property_desc,
3096 	DBusMessageIter *iter, DBusError *error, void *user_data)
3097 {
3098 	struct wpa_supplicant *wpa_s = user_data;
3099 	struct wpa_driver_capa capa;
3100 	int res;
3101 	DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
3102 		variant_iter;
3103 	const char *scans[] = { "active", "passive", "ssid" };
3104 
3105 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3106 					      "a{sv}", &variant_iter) ||
3107 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3108 		goto nomem;
3109 
3110 	res = wpa_drv_get_capa(wpa_s, &capa);
3111 
3112 	/***** pairwise cipher */
3113 	if (res < 0) {
3114 #ifdef CONFIG_NO_TKIP
3115 		const char *args[] = {"ccmp", "none"};
3116 #else /* CONFIG_NO_TKIP */
3117 		const char *args[] = {"ccmp", "tkip", "none"};
3118 #endif /* CONFIG_NO_TKIP */
3119 
3120 		if (!wpa_dbus_dict_append_string_array(
3121 			    &iter_dict, "Pairwise", args,
3122 			    ARRAY_SIZE(args)))
3123 			goto nomem;
3124 	} else {
3125 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
3126 						      &iter_dict_entry,
3127 						      &iter_dict_val,
3128 						      &iter_array) ||
3129 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
3130 		     !wpa_dbus_dict_string_array_add_element(
3131 			     &iter_array, "ccmp-256")) ||
3132 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
3133 		     !wpa_dbus_dict_string_array_add_element(
3134 			     &iter_array, "gcmp-256")) ||
3135 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
3136 		     !wpa_dbus_dict_string_array_add_element(
3137 			     &iter_array, "ccmp")) ||
3138 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
3139 		     !wpa_dbus_dict_string_array_add_element(
3140 			     &iter_array, "gcmp")) ||
3141 #ifndef CONFIG_NO_TKIP
3142 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
3143 		     !wpa_dbus_dict_string_array_add_element(
3144 			     &iter_array, "tkip")) ||
3145 #endif /* CONFIG_NO_TKIP */
3146 		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
3147 		     !wpa_dbus_dict_string_array_add_element(
3148 			     &iter_array, "none")) ||
3149 		    !wpa_dbus_dict_end_string_array(&iter_dict,
3150 						    &iter_dict_entry,
3151 						    &iter_dict_val,
3152 						    &iter_array))
3153 			goto nomem;
3154 	}
3155 
3156 	/***** group cipher */
3157 	if (res < 0) {
3158 		const char *args[] = {
3159 			"ccmp",
3160 #ifndef CONFIG_NO_TKIP
3161 			"tkip",
3162 #endif /* CONFIG_NO_TKIP */
3163 #ifdef CONFIG_WEP
3164 			"wep104", "wep40"
3165 #endif /* CONFIG_WEP */
3166 		};
3167 
3168 		if (!wpa_dbus_dict_append_string_array(
3169 			    &iter_dict, "Group", args,
3170 			    ARRAY_SIZE(args)))
3171 			goto nomem;
3172 	} else {
3173 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
3174 						      &iter_dict_entry,
3175 						      &iter_dict_val,
3176 						      &iter_array) ||
3177 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
3178 		     !wpa_dbus_dict_string_array_add_element(
3179 			     &iter_array, "ccmp-256")) ||
3180 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
3181 		     !wpa_dbus_dict_string_array_add_element(
3182 			     &iter_array, "gcmp-256")) ||
3183 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
3184 		     !wpa_dbus_dict_string_array_add_element(
3185 			     &iter_array, "ccmp")) ||
3186 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
3187 		     !wpa_dbus_dict_string_array_add_element(
3188 			     &iter_array, "gcmp")) ||
3189 #ifndef CONFIG_NO_TKIP
3190 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
3191 		     !wpa_dbus_dict_string_array_add_element(
3192 			     &iter_array, "tkip")) ||
3193 #endif /* CONFIG_NO_TKIP */
3194 #ifdef CONFIG_WEP
3195 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
3196 		     !wpa_dbus_dict_string_array_add_element(
3197 			     &iter_array, "wep104")) ||
3198 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
3199 		     !wpa_dbus_dict_string_array_add_element(
3200 			     &iter_array, "wep40")) ||
3201 #endif /* CONFIG_WEP */
3202 		    !wpa_dbus_dict_end_string_array(&iter_dict,
3203 						    &iter_dict_entry,
3204 						    &iter_dict_val,
3205 						    &iter_array))
3206 			goto nomem;
3207 	}
3208 
3209 	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "GroupMgmt",
3210 					      &iter_dict_entry,
3211 					      &iter_dict_val,
3212 					      &iter_array) ||
3213 	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP) &&
3214 	     !wpa_dbus_dict_string_array_add_element(
3215 		     &iter_array, "aes-128-cmac")) ||
3216 	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_128) &&
3217 	     !wpa_dbus_dict_string_array_add_element(
3218 		     &iter_array, "bip-gmac-128")) ||
3219 	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_256) &&
3220 	     !wpa_dbus_dict_string_array_add_element(
3221 		     &iter_array, "bip-gmac-256")) ||
3222 	    (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_CMAC_256) &&
3223 	     !wpa_dbus_dict_string_array_add_element(
3224 		     &iter_array, "bip-cmac-256")) ||
3225 	    !wpa_dbus_dict_end_string_array(&iter_dict,
3226 					    &iter_dict_entry,
3227 					    &iter_dict_val,
3228 					    &iter_array))
3229 		goto nomem;
3230 
3231 	/***** key management */
3232 	if (res < 0) {
3233 		const char *args[] = {
3234 			"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
3235 #ifdef CONFIG_WPS
3236 			"wps",
3237 #endif /* CONFIG_WPS */
3238 			"none"
3239 		};
3240 		if (!wpa_dbus_dict_append_string_array(
3241 			    &iter_dict, "KeyMgmt", args,
3242 			    ARRAY_SIZE(args)))
3243 			goto nomem;
3244 	} else {
3245 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
3246 						      &iter_dict_entry,
3247 						      &iter_dict_val,
3248 						      &iter_array) ||
3249 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
3250 							    "none") ||
3251 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
3252 							    "ieee8021x"))
3253 			goto nomem;
3254 
3255 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3256 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
3257 			if (!wpa_dbus_dict_string_array_add_element(
3258 				    &iter_array, "wpa-eap"))
3259 				goto nomem;
3260 
3261 #ifdef CONFIG_IEEE80211R
3262 			if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
3263 			     !wpa_dbus_dict_string_array_add_element(
3264 				     &iter_array, "wpa-ft-eap"))
3265 				goto nomem;
3266 #endif /* CONFIG_IEEE80211R */
3267 
3268 /* TODO: Ensure that driver actually supports sha256 encryption. */
3269 			if (!wpa_dbus_dict_string_array_add_element(
3270 				    &iter_array, "wpa-eap-sha256"))
3271 				goto nomem;
3272 		}
3273 
3274 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
3275 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
3276 			if (!wpa_dbus_dict_string_array_add_element(
3277 				    &iter_array, "wpa-psk"))
3278 				goto nomem;
3279 
3280 #ifdef CONFIG_IEEE80211R
3281 			if ((capa.key_mgmt &
3282 			      WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
3283 			     !wpa_dbus_dict_string_array_add_element(
3284 				     &iter_array, "wpa-ft-psk"))
3285 				goto nomem;
3286 #endif /* CONFIG_IEEE80211R */
3287 
3288 /* TODO: Ensure that driver actually supports sha256 encryption. */
3289 			if (!wpa_dbus_dict_string_array_add_element(
3290 				    &iter_array, "wpa-psk-sha256"))
3291 				goto nomem;
3292 		}
3293 
3294 		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
3295 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
3296 							    "wpa-none"))
3297 			goto nomem;
3298 
3299 
3300 #ifdef CONFIG_WPS
3301 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
3302 							    "wps"))
3303 			goto nomem;
3304 #endif /* CONFIG_WPS */
3305 
3306 #ifdef CONFIG_SAE
3307 		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
3308 		    !wpa_dbus_dict_string_array_add_element(&iter_array, "sae"))
3309 			goto nomem;
3310 #endif /* CONFIG_SAE */
3311 
3312 #ifdef CONFIG_OWE
3313 		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) &&
3314 		    !wpa_dbus_dict_string_array_add_element(&iter_array, "owe"))
3315 			goto nomem;
3316 #endif /* CONFIG_OWE */
3317 
3318 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
3319 						    &iter_dict_entry,
3320 						    &iter_dict_val,
3321 						    &iter_array))
3322 			goto nomem;
3323 	}
3324 
3325 	/***** WPA protocol */
3326 	if (res < 0) {
3327 		const char *args[] = { "rsn", "wpa" };
3328 
3329 		if (!wpa_dbus_dict_append_string_array(
3330 			    &iter_dict, "Protocol", args,
3331 			    ARRAY_SIZE(args)))
3332 			goto nomem;
3333 	} else {
3334 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
3335 						      &iter_dict_entry,
3336 						      &iter_dict_val,
3337 						      &iter_array) ||
3338 		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
3339 				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
3340 		     !wpa_dbus_dict_string_array_add_element(
3341 			     &iter_array, "rsn")) ||
3342 		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3343 				       WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
3344 		     !wpa_dbus_dict_string_array_add_element(
3345 			     &iter_array, "wpa")) ||
3346 		    !wpa_dbus_dict_end_string_array(&iter_dict,
3347 						    &iter_dict_entry,
3348 						    &iter_dict_val,
3349 						    &iter_array))
3350 			goto nomem;
3351 	}
3352 
3353 	/***** auth alg */
3354 	if (res < 0) {
3355 		const char *args[] = { "open", "shared", "leap" };
3356 
3357 		if (!wpa_dbus_dict_append_string_array(
3358 			    &iter_dict, "AuthAlg", args,
3359 			    ARRAY_SIZE(args)))
3360 			goto nomem;
3361 	} else {
3362 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
3363 						      &iter_dict_entry,
3364 						      &iter_dict_val,
3365 						      &iter_array))
3366 			goto nomem;
3367 
3368 		if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
3369 		     !wpa_dbus_dict_string_array_add_element(
3370 			     &iter_array, "open")) ||
3371 		    ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
3372 		     !wpa_dbus_dict_string_array_add_element(
3373 			     &iter_array, "shared")) ||
3374 		    ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
3375 		     !wpa_dbus_dict_string_array_add_element(
3376 			     &iter_array, "leap")) ||
3377 		    !wpa_dbus_dict_end_string_array(&iter_dict,
3378 						    &iter_dict_entry,
3379 						    &iter_dict_val,
3380 						    &iter_array))
3381 			goto nomem;
3382 	}
3383 
3384 	/***** Scan */
3385 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
3386 					       ARRAY_SIZE(scans)))
3387 		goto nomem;
3388 
3389 	/***** Modes */
3390 	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
3391 					      &iter_dict_entry,
3392 					      &iter_dict_val,
3393 					      &iter_array) ||
3394 	    !wpa_dbus_dict_string_array_add_element(
3395 		    &iter_array, "infrastructure") ||
3396 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) &&
3397 	     !wpa_dbus_dict_string_array_add_element(
3398 		     &iter_array, "ad-hoc")) ||
3399 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
3400 	     !wpa_dbus_dict_string_array_add_element(
3401 		     &iter_array, "ap")) ||
3402 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
3403 	     !wpa_s->conf->p2p_disabled &&
3404 	     !wpa_dbus_dict_string_array_add_element(
3405 		     &iter_array, "p2p")) ||
3406 #ifdef CONFIG_MESH
3407 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_MESH) &&
3408 	     !wpa_dbus_dict_string_array_add_element(
3409 		     &iter_array, "mesh")) ||
3410 #endif /* CONFIG_MESH */
3411 	    !wpa_dbus_dict_end_string_array(&iter_dict,
3412 					    &iter_dict_entry,
3413 					    &iter_dict_val,
3414 					    &iter_array))
3415 		goto nomem;
3416 	/***** Modes end */
3417 
3418 	if (res >= 0) {
3419 		dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
3420 
3421 		if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
3422 						max_scan_ssid))
3423 			goto nomem;
3424 	}
3425 
3426 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
3427 	    !dbus_message_iter_close_container(iter, &variant_iter))
3428 		goto nomem;
3429 
3430 	return TRUE;
3431 
3432 nomem:
3433 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3434 	return FALSE;
3435 }
3436 
3437 
3438 /**
3439  * wpas_dbus_getter_state - Get interface state
3440  * @iter: Pointer to incoming dbus message iter
3441  * @error: Location to store error on failure
3442  * @user_data: Function specific data
3443  * Returns: TRUE on success, FALSE on failure
3444  *
3445  * Getter for "State" property.
3446  */
wpas_dbus_getter_state(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3447 dbus_bool_t wpas_dbus_getter_state(
3448 	const struct wpa_dbus_property_desc *property_desc,
3449 	DBusMessageIter *iter, DBusError *error, void *user_data)
3450 {
3451 	struct wpa_supplicant *wpa_s = user_data;
3452 	const char *str_state;
3453 	char *state_ls, *tmp;
3454 	dbus_bool_t success = FALSE;
3455 
3456 	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
3457 
3458 	/* make state string lowercase to fit new DBus API convention
3459 	 */
3460 	state_ls = tmp = os_strdup(str_state);
3461 	if (!tmp) {
3462 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3463 		return FALSE;
3464 	}
3465 	while (*tmp) {
3466 		*tmp = tolower(*tmp);
3467 		tmp++;
3468 	}
3469 
3470 	success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3471 						   &state_ls, error);
3472 
3473 	os_free(state_ls);
3474 
3475 	return success;
3476 }
3477 
3478 
3479 /**
3480  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
3481  * @iter: Pointer to incoming dbus message iter
3482  * @error: Location to store error on failure
3483  * @user_data: Function specific data
3484  * Returns: TRUE on success, FALSE on failure
3485  *
3486  * Getter for "scanning" property.
3487  */
wpas_dbus_getter_scanning(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3488 dbus_bool_t wpas_dbus_getter_scanning(
3489 	const struct wpa_dbus_property_desc *property_desc,
3490 	DBusMessageIter *iter, DBusError *error, void *user_data)
3491 {
3492 	struct wpa_supplicant *wpa_s = user_data;
3493 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
3494 
3495 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3496 						&scanning, error);
3497 }
3498 
3499 
3500 /**
3501  * wpas_dbus_getter_ap_scan - Control roaming mode
3502  * @iter: Pointer to incoming dbus message iter
3503  * @error: Location to store error on failure
3504  * @user_data: Function specific data
3505  * Returns: TRUE on success, FALSE on failure
3506  *
3507  * Getter function for "ApScan" property.
3508  */
wpas_dbus_getter_ap_scan(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3509 dbus_bool_t wpas_dbus_getter_ap_scan(
3510 	const struct wpa_dbus_property_desc *property_desc,
3511 	DBusMessageIter *iter, DBusError *error, void *user_data)
3512 {
3513 	struct wpa_supplicant *wpa_s = user_data;
3514 	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
3515 
3516 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3517 						&ap_scan, error);
3518 }
3519 
3520 
3521 /**
3522  * wpas_dbus_setter_ap_scan - Control roaming mode
3523  * @iter: Pointer to incoming dbus message iter
3524  * @error: Location to store error on failure
3525  * @user_data: Function specific data
3526  * Returns: TRUE on success, FALSE on failure
3527  *
3528  * Setter function for "ApScan" property.
3529  */
wpas_dbus_setter_ap_scan(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3530 dbus_bool_t wpas_dbus_setter_ap_scan(
3531 	const struct wpa_dbus_property_desc *property_desc,
3532 	DBusMessageIter *iter, DBusError *error, void *user_data)
3533 {
3534 	struct wpa_supplicant *wpa_s = user_data;
3535 	dbus_uint32_t ap_scan;
3536 
3537 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3538 					      &ap_scan))
3539 		return FALSE;
3540 
3541 	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
3542 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3543 				     "ap_scan must be 0, 1, or 2");
3544 		return FALSE;
3545 	}
3546 	return TRUE;
3547 }
3548 
3549 
3550 /**
3551  * wpas_dbus_getter_fast_reauth - Control fast
3552  * reauthentication (TLS session resumption)
3553  * @iter: Pointer to incoming dbus message iter
3554  * @error: Location to store error on failure
3555  * @user_data: Function specific data
3556  * Returns: TRUE on success, FALSE on failure
3557  *
3558  * Getter function for "FastReauth" property.
3559  */
wpas_dbus_getter_fast_reauth(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3560 dbus_bool_t wpas_dbus_getter_fast_reauth(
3561 	const struct wpa_dbus_property_desc *property_desc,
3562 	DBusMessageIter *iter, DBusError *error, void *user_data)
3563 {
3564 	struct wpa_supplicant *wpa_s = user_data;
3565 	dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
3566 
3567 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3568 						&fast_reauth, error);
3569 }
3570 
3571 
3572 /**
3573  * wpas_dbus_setter_fast_reauth - Control fast
3574  * reauthentication (TLS session resumption)
3575  * @iter: Pointer to incoming dbus message iter
3576  * @error: Location to store error on failure
3577  * @user_data: Function specific data
3578  * Returns: TRUE on success, FALSE on failure
3579  *
3580  * Setter function for "FastReauth" property.
3581  */
wpas_dbus_setter_fast_reauth(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3582 dbus_bool_t wpas_dbus_setter_fast_reauth(
3583 	const struct wpa_dbus_property_desc *property_desc,
3584 	DBusMessageIter *iter, DBusError *error, void *user_data)
3585 {
3586 	struct wpa_supplicant *wpa_s = user_data;
3587 	dbus_bool_t fast_reauth;
3588 
3589 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
3590 					      &fast_reauth))
3591 		return FALSE;
3592 
3593 	wpa_s->conf->fast_reauth = fast_reauth;
3594 	return TRUE;
3595 }
3596 
3597 
3598 /**
3599  * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
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  * Getter for "DisconnectReason" property.  The reason is negative if it is
3606  * locally generated.
3607  */
wpas_dbus_getter_disconnect_reason(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3608 dbus_bool_t wpas_dbus_getter_disconnect_reason(
3609 	const struct wpa_dbus_property_desc *property_desc,
3610 	DBusMessageIter *iter, DBusError *error, void *user_data)
3611 {
3612 	struct wpa_supplicant *wpa_s = user_data;
3613 	dbus_int32_t reason = wpa_s->disconnect_reason;
3614 
3615 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3616 						&reason, error);
3617 }
3618 
3619 
3620 /**
3621  * wpas_dbus_getter_auth_status_code - Get most recent auth status code
3622  * @iter: Pointer to incoming dbus message iter
3623  * @error: Location to store error on failure
3624  * @user_data: Function specific data
3625  * Returns: TRUE on success, FALSE on failure
3626  *
3627  * Getter for "AuthStatusCode" property.
3628  */
wpas_dbus_getter_auth_status_code(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3629 dbus_bool_t wpas_dbus_getter_auth_status_code(
3630 	const struct wpa_dbus_property_desc *property_desc,
3631 	DBusMessageIter *iter, DBusError *error, void *user_data)
3632 {
3633 	struct wpa_supplicant *wpa_s = user_data;
3634 	dbus_int32_t reason = wpa_s->auth_status_code;
3635 
3636 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3637 						&reason, error);
3638 }
3639 
3640 
3641 /**
3642  * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code
3643  * @iter: Pointer to incoming dbus message iter
3644  * @error: Location to store error on failure
3645  * @user_data: Function specific data
3646  * Returns: TRUE on success, FALSE on failure
3647  *
3648  * Getter for "AssocStatusCode" property.
3649  */
wpas_dbus_getter_assoc_status_code(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3650 dbus_bool_t wpas_dbus_getter_assoc_status_code(
3651 	const struct wpa_dbus_property_desc *property_desc,
3652 	DBusMessageIter *iter, DBusError *error, void *user_data)
3653 {
3654 	struct wpa_supplicant *wpa_s = user_data;
3655 	dbus_int32_t status_code = wpa_s->assoc_status_code;
3656 
3657 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3658 						&status_code, error);
3659 }
3660 
3661 
3662 /**
3663  * wpas_dbus_getter_roam_time - Get most recent roam time
3664  * @iter: Pointer to incoming dbus message iter
3665  * @error: Location to store error on failure
3666  * @user_data: Function specific data
3667  * Returns: TRUE on success, FALSE on failure
3668  *
3669  * Getter for "RoamTime" property.
3670  */
wpas_dbus_getter_roam_time(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3671 dbus_bool_t wpas_dbus_getter_roam_time(
3672 	const struct wpa_dbus_property_desc *property_desc,
3673 	DBusMessageIter *iter, DBusError *error, void *user_data)
3674 {
3675 	struct wpa_supplicant *wpa_s = user_data;
3676 	dbus_uint32_t roam_time = wpa_s->roam_time.sec * 1000 +
3677 		wpa_s->roam_time.usec / 1000;
3678 
3679 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3680 						&roam_time, error);
3681 }
3682 
3683 
3684 /**
3685  * wpas_dbus_getter_roam_complete - Get most recent roam success or failure
3686  * @iter: Pointer to incoming dbus message iter
3687  * @error: Location to store error on failure
3688  * @user_data: Function specific data
3689  * Returns: TRUE on success, FALSE on failure
3690  *
3691  * Getter for "RoamComplete" property.
3692  */
wpas_dbus_getter_roam_complete(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3693 dbus_bool_t wpas_dbus_getter_roam_complete(
3694 	const struct wpa_dbus_property_desc *property_desc,
3695 	DBusMessageIter *iter, DBusError *error, void *user_data)
3696 {
3697 	struct wpa_supplicant *wpa_s = user_data;
3698 	dbus_bool_t roam_complete = os_reltime_initialized(&wpa_s->roam_time);
3699 
3700 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3701 						&roam_complete, error);
3702 }
3703 
3704 
3705 /**
3706  * wpas_dbus_getter_session_length - Get most recent BSS session length
3707  * @iter: Pointer to incoming dbus message iter
3708  * @error: Location to store error on failure
3709  * @user_data: Function specific data
3710  * Returns: TRUE on success, FALSE on failure
3711  *
3712  * Getter for "SessionLength" property.
3713  */
wpas_dbus_getter_session_length(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3714 dbus_bool_t wpas_dbus_getter_session_length(
3715 	const struct wpa_dbus_property_desc *property_desc,
3716 	DBusMessageIter *iter, DBusError *error, void *user_data)
3717 {
3718 	struct wpa_supplicant *wpa_s = user_data;
3719 	dbus_uint32_t session_length = wpa_s->session_length.sec * 1000 +
3720 		wpa_s->session_length.usec / 1000;
3721 
3722 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3723 						&session_length, error);
3724 }
3725 
3726 
3727 /**
3728  * wpas_dbus_getter_bss_tm_status - Get most BSS Transition Management request
3729  * status code
3730  * @iter: Pointer to incoming dbus message iter
3731  * @error: Location to store error on failure
3732  * @user_data: Function specific data
3733  * Returns: TRUE on success, FALSE on failure
3734  *
3735  * Getter for "BSSTMStatus" property.
3736  */
wpas_dbus_getter_bss_tm_status(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3737 dbus_bool_t wpas_dbus_getter_bss_tm_status(
3738 	const struct wpa_dbus_property_desc *property_desc,
3739 	DBusMessageIter *iter, DBusError *error, void *user_data)
3740 {
3741 #ifdef CONFIG_WNM
3742 	struct wpa_supplicant *wpa_s = user_data;
3743 	dbus_uint32_t bss_tm_status = wpa_s->bss_tm_status;
3744 #else /* CONFIG_WNM */
3745 	dbus_uint32_t bss_tm_status = 0;
3746 #endif /* CONFIG_WNM */
3747 
3748 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3749 						&bss_tm_status, error);
3750 }
3751 
3752 
3753 /**
3754  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
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 function for "BSSExpireAge" property.
3761  */
wpas_dbus_getter_bss_expire_age(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3762 dbus_bool_t wpas_dbus_getter_bss_expire_age(
3763 	const struct wpa_dbus_property_desc *property_desc,
3764 	DBusMessageIter *iter, DBusError *error, void *user_data)
3765 {
3766 	struct wpa_supplicant *wpa_s = user_data;
3767 	dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
3768 
3769 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3770 						&expire_age, error);
3771 }
3772 
3773 
3774 /**
3775  * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
3776  * @iter: Pointer to incoming dbus message iter
3777  * @error: Location to store error on failure
3778  * @user_data: Function specific data
3779  * Returns: TRUE on success, FALSE on failure
3780  *
3781  * Setter function for "BSSExpireAge" property.
3782  */
wpas_dbus_setter_bss_expire_age(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3783 dbus_bool_t wpas_dbus_setter_bss_expire_age(
3784 	const struct wpa_dbus_property_desc *property_desc,
3785 	DBusMessageIter *iter, DBusError *error, void *user_data)
3786 {
3787 	struct wpa_supplicant *wpa_s = user_data;
3788 	dbus_uint32_t expire_age;
3789 
3790 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3791 					      &expire_age))
3792 		return FALSE;
3793 
3794 	if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
3795 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3796 				     "BSSExpireAge must be >= 10");
3797 		return FALSE;
3798 	}
3799 	return TRUE;
3800 }
3801 
3802 
3803 /**
3804  * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
3805  * @iter: Pointer to incoming dbus message iter
3806  * @error: Location to store error on failure
3807  * @user_data: Function specific data
3808  * Returns: TRUE on success, FALSE on failure
3809  *
3810  * Getter function for "BSSExpireCount" property.
3811  */
wpas_dbus_getter_bss_expire_count(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3812 dbus_bool_t wpas_dbus_getter_bss_expire_count(
3813 	const struct wpa_dbus_property_desc *property_desc,
3814 	DBusMessageIter *iter, DBusError *error, void *user_data)
3815 {
3816 	struct wpa_supplicant *wpa_s = user_data;
3817 	dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
3818 
3819 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3820 						&expire_count, error);
3821 }
3822 
3823 
3824 /**
3825  * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
3826  * @iter: Pointer to incoming dbus message iter
3827  * @error: Location to store error on failure
3828  * @user_data: Function specific data
3829  * Returns: TRUE on success, FALSE on failure
3830  *
3831  * Setter function for "BSSExpireCount" property.
3832  */
wpas_dbus_setter_bss_expire_count(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3833 dbus_bool_t wpas_dbus_setter_bss_expire_count(
3834 	const struct wpa_dbus_property_desc *property_desc,
3835 	DBusMessageIter *iter, DBusError *error, void *user_data)
3836 {
3837 	struct wpa_supplicant *wpa_s = user_data;
3838 	dbus_uint32_t expire_count;
3839 
3840 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3841 					      &expire_count))
3842 		return FALSE;
3843 
3844 	if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
3845 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3846 				     "BSSExpireCount must be > 0");
3847 		return FALSE;
3848 	}
3849 	return TRUE;
3850 }
3851 
3852 
3853 /**
3854  * wpas_dbus_getter_country - Control country code
3855  * @iter: Pointer to incoming dbus message iter
3856  * @error: Location to store error on failure
3857  * @user_data: Function specific data
3858  * Returns: TRUE on success, FALSE on failure
3859  *
3860  * Getter function for "Country" property.
3861  */
wpas_dbus_getter_country(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3862 dbus_bool_t wpas_dbus_getter_country(
3863 	const struct wpa_dbus_property_desc *property_desc,
3864 	DBusMessageIter *iter, DBusError *error, void *user_data)
3865 {
3866 	struct wpa_supplicant *wpa_s = user_data;
3867 	char country[3];
3868 	char *str = country;
3869 
3870 	country[0] = wpa_s->conf->country[0];
3871 	country[1] = wpa_s->conf->country[1];
3872 	country[2] = '\0';
3873 
3874 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3875 						&str, error);
3876 }
3877 
3878 
3879 /**
3880  * wpas_dbus_setter_country - Control country code
3881  * @iter: Pointer to incoming dbus message iter
3882  * @error: Location to store error on failure
3883  * @user_data: Function specific data
3884  * Returns: TRUE on success, FALSE on failure
3885  *
3886  * Setter function for "Country" property.
3887  */
wpas_dbus_setter_country(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3888 dbus_bool_t wpas_dbus_setter_country(
3889 	const struct wpa_dbus_property_desc *property_desc,
3890 	DBusMessageIter *iter, DBusError *error, void *user_data)
3891 {
3892 	struct wpa_supplicant *wpa_s = user_data;
3893 	const char *country;
3894 
3895 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
3896 					      &country))
3897 		return FALSE;
3898 
3899 	if (!country[0] || !country[1]) {
3900 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3901 				     "invalid country code");
3902 		return FALSE;
3903 	}
3904 
3905 	if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
3906 		wpa_printf(MSG_DEBUG, "Failed to set country");
3907 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3908 				     "failed to set country code");
3909 		return FALSE;
3910 	}
3911 
3912 	wpa_s->conf->country[0] = country[0];
3913 	wpa_s->conf->country[1] = country[1];
3914 	return TRUE;
3915 }
3916 
3917 
3918 /**
3919  * wpas_dbus_getter_scan_interval - Get scan interval
3920  * @iter: Pointer to incoming dbus message iter
3921  * @error: Location to store error on failure
3922  * @user_data: Function specific data
3923  * Returns: TRUE on success, FALSE on failure
3924  *
3925  * Getter function for "ScanInterval" property.
3926  */
wpas_dbus_getter_scan_interval(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3927 dbus_bool_t wpas_dbus_getter_scan_interval(
3928 	const struct wpa_dbus_property_desc *property_desc,
3929 	DBusMessageIter *iter, DBusError *error, void *user_data)
3930 {
3931 	struct wpa_supplicant *wpa_s = user_data;
3932 	dbus_int32_t scan_interval = wpa_s->scan_interval;
3933 
3934 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3935 						&scan_interval, error);
3936 }
3937 
3938 
3939 /**
3940  * wpas_dbus_setter_scan_interval - Control scan interval
3941  * @iter: Pointer to incoming dbus message iter
3942  * @error: Location to store error on failure
3943  * @user_data: Function specific data
3944  * Returns: TRUE on success, FALSE on failure
3945  *
3946  * Setter function for "ScanInterval" property.
3947  */
wpas_dbus_setter_scan_interval(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3948 dbus_bool_t wpas_dbus_setter_scan_interval(
3949 	const struct wpa_dbus_property_desc *property_desc,
3950 	DBusMessageIter *iter, DBusError *error, void *user_data)
3951 {
3952 	struct wpa_supplicant *wpa_s = user_data;
3953 	dbus_int32_t scan_interval;
3954 
3955 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
3956 					      &scan_interval))
3957 		return FALSE;
3958 
3959 	if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
3960 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3961 				     "scan_interval must be >= 0");
3962 		return FALSE;
3963 	}
3964 	return TRUE;
3965 }
3966 
3967 
3968 /**
3969  * wpas_dbus_getter_ifname - Get interface name
3970  * @iter: Pointer to incoming dbus message iter
3971  * @error: Location to store error on failure
3972  * @user_data: Function specific data
3973  * Returns: TRUE on success, FALSE on failure
3974  *
3975  * Getter for "Ifname" property.
3976  */
wpas_dbus_getter_ifname(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3977 dbus_bool_t wpas_dbus_getter_ifname(
3978 	const struct wpa_dbus_property_desc *property_desc,
3979 	DBusMessageIter *iter, DBusError *error, void *user_data)
3980 {
3981 	struct wpa_supplicant *wpa_s = user_data;
3982 
3983 	return wpas_dbus_string_property_getter(iter, wpa_s->ifname, error);
3984 }
3985 
3986 
3987 /**
3988  * wpas_dbus_getter_driver - Get interface name
3989  * @iter: Pointer to incoming dbus message iter
3990  * @error: Location to store error on failure
3991  * @user_data: Function specific data
3992  * Returns: TRUE on success, FALSE on failure
3993  *
3994  * Getter for "Driver" property.
3995  */
wpas_dbus_getter_driver(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3996 dbus_bool_t wpas_dbus_getter_driver(
3997 	const struct wpa_dbus_property_desc *property_desc,
3998 	DBusMessageIter *iter, DBusError *error, void *user_data)
3999 {
4000 	struct wpa_supplicant *wpa_s = user_data;
4001 
4002 	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
4003 		wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
4004 			   __func__);
4005 		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
4006 			       __func__);
4007 		return FALSE;
4008 	}
4009 
4010 	return wpas_dbus_string_property_getter(iter, wpa_s->driver->name,
4011 						error);
4012 }
4013 
4014 
4015 /**
4016  * wpas_dbus_getter_current_bss - Get current bss object path
4017  * @iter: Pointer to incoming dbus message iter
4018  * @error: Location to store error on failure
4019  * @user_data: Function specific data
4020  * Returns: TRUE on success, FALSE on failure
4021  *
4022  * Getter for "CurrentBSS" property.
4023  */
wpas_dbus_getter_current_bss(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4024 dbus_bool_t wpas_dbus_getter_current_bss(
4025 	const struct wpa_dbus_property_desc *property_desc,
4026 	DBusMessageIter *iter, DBusError *error, void *user_data)
4027 {
4028 	struct wpa_supplicant *wpa_s = user_data;
4029 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
4030 
4031 	if (wpa_s->current_bss && wpa_s->dbus_new_path)
4032 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
4033 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
4034 			    wpa_s->dbus_new_path, wpa_s->current_bss->id);
4035 	else
4036 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
4037 
4038 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
4039 						&bss_obj_path, error);
4040 }
4041 
4042 
4043 /**
4044  * wpas_dbus_getter_current_network - Get current network object path
4045  * @iter: Pointer to incoming dbus message iter
4046  * @error: Location to store error on failure
4047  * @user_data: Function specific data
4048  * Returns: TRUE on success, FALSE on failure
4049  *
4050  * Getter for "CurrentNetwork" property.
4051  */
wpas_dbus_getter_current_network(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4052 dbus_bool_t wpas_dbus_getter_current_network(
4053 	const struct wpa_dbus_property_desc *property_desc,
4054 	DBusMessageIter *iter, DBusError *error, void *user_data)
4055 {
4056 	struct wpa_supplicant *wpa_s = user_data;
4057 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
4058 
4059 	if (wpa_s->current_ssid && wpa_s->dbus_new_path)
4060 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
4061 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
4062 			    wpa_s->dbus_new_path, wpa_s->current_ssid->id);
4063 	else
4064 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
4065 
4066 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
4067 						&net_obj_path, error);
4068 }
4069 
4070 
4071 /**
4072  * wpas_dbus_getter_current_auth_mode - Get current authentication type
4073  * @iter: Pointer to incoming dbus message iter
4074  * @error: Location to store error on failure
4075  * @user_data: Function specific data
4076  * Returns: TRUE on success, FALSE on failure
4077  *
4078  * Getter for "CurrentAuthMode" property.
4079  */
wpas_dbus_getter_current_auth_mode(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4080 dbus_bool_t wpas_dbus_getter_current_auth_mode(
4081 	const struct wpa_dbus_property_desc *property_desc,
4082 	DBusMessageIter *iter, DBusError *error, void *user_data)
4083 {
4084 	struct wpa_supplicant *wpa_s = user_data;
4085 	const char *eap_mode;
4086 	const char *auth_mode;
4087 	char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
4088 
4089 	if (wpa_s->wpa_state <= WPA_SCANNING) {
4090 		auth_mode = "INACTIVE";
4091 	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
4092 	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
4093 		eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
4094 		os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
4095 			    "EAP-%s", eap_mode);
4096 		auth_mode = eap_mode_buf;
4097 
4098 	} else if (wpa_s->current_ssid) {
4099 		auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
4100 					     wpa_s->current_ssid->proto);
4101 	} else {
4102 		auth_mode = "UNKNOWN";
4103 	}
4104 
4105 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
4106 						&auth_mode, error);
4107 }
4108 
4109 
4110 /**
4111  * wpas_dbus_getter_bridge_ifname - Get interface name
4112  * @iter: Pointer to incoming dbus message iter
4113  * @error: Location to store error on failure
4114  * @user_data: Function specific data
4115  * Returns: TRUE on success, FALSE on failure
4116  *
4117  * Getter for "BridgeIfname" property.
4118  */
wpas_dbus_getter_bridge_ifname(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4119 dbus_bool_t wpas_dbus_getter_bridge_ifname(
4120 	const struct wpa_dbus_property_desc *property_desc,
4121 	DBusMessageIter *iter, DBusError *error, void *user_data)
4122 {
4123 	struct wpa_supplicant *wpa_s = user_data;
4124 
4125 	return wpas_dbus_string_property_getter(iter, wpa_s->bridge_ifname,
4126 						error);
4127 }
4128 
4129 
wpas_dbus_setter_bridge_ifname(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4130 dbus_bool_t wpas_dbus_setter_bridge_ifname(
4131 	const struct wpa_dbus_property_desc *property_desc,
4132 	DBusMessageIter *iter, DBusError *error, void *user_data)
4133 {
4134 	struct wpa_supplicant *wpa_s = user_data;
4135 	const char *bridge_ifname = NULL;
4136 	const char *msg;
4137 	int r;
4138 
4139 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
4140 					      &bridge_ifname))
4141 		return FALSE;
4142 
4143 	r = wpa_supplicant_update_bridge_ifname(wpa_s, bridge_ifname);
4144 	if (r != 0) {
4145 		switch (r) {
4146 		case -EINVAL:
4147 			msg = "invalid interface name";
4148 			break;
4149 		case -EBUSY:
4150 			msg = "interface is busy";
4151 			break;
4152 		case -EIO:
4153 			msg = "socket error";
4154 			break;
4155 		default:
4156 			msg = "unknown error";
4157 			break;
4158 		}
4159 		dbus_set_error_const(error, DBUS_ERROR_FAILED, msg);
4160 		return FALSE;
4161 	}
4162 
4163 	return TRUE;
4164 }
4165 
4166 
4167 /**
4168  * wpas_dbus_getter_config_file - Get interface configuration file path
4169  * @iter: Pointer to incoming dbus message iter
4170  * @error: Location to store error on failure
4171  * @user_data: Function specific data
4172  * Returns: TRUE on success, FALSE on failure
4173  *
4174  * Getter for "ConfigFile" property.
4175  */
wpas_dbus_getter_config_file(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4176 dbus_bool_t wpas_dbus_getter_config_file(
4177 	const struct wpa_dbus_property_desc *property_desc,
4178 	DBusMessageIter *iter, DBusError *error, void *user_data)
4179 {
4180 	struct wpa_supplicant *wpa_s = user_data;
4181 
4182 	return wpas_dbus_string_property_getter(iter, wpa_s->confname, error);
4183 }
4184 
4185 
4186 /**
4187  * wpas_dbus_getter_bsss - Get array of BSSs objects
4188  * @iter: Pointer to incoming dbus message iter
4189  * @error: Location to store error on failure
4190  * @user_data: Function specific data
4191  * Returns: TRUE on success, FALSE on failure
4192  *
4193  * Getter for "BSSs" property.
4194  */
wpas_dbus_getter_bsss(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4195 dbus_bool_t wpas_dbus_getter_bsss(
4196 	const struct wpa_dbus_property_desc *property_desc,
4197 	DBusMessageIter *iter, DBusError *error, void *user_data)
4198 {
4199 	struct wpa_supplicant *wpa_s = user_data;
4200 	struct wpa_bss *bss;
4201 	char **paths;
4202 	unsigned int i = 0;
4203 	dbus_bool_t success = FALSE;
4204 
4205 	if (!wpa_s->dbus_new_path) {
4206 		dbus_set_error(error, DBUS_ERROR_FAILED,
4207 			       "%s: no D-Bus interface", __func__);
4208 		return FALSE;
4209 	}
4210 
4211 	paths = os_calloc(wpa_s->num_bss, sizeof(char *));
4212 	if (!paths) {
4213 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4214 		return FALSE;
4215 	}
4216 
4217 	/* Loop through scan results and append each result's object path */
4218 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
4219 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
4220 		if (paths[i] == NULL) {
4221 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4222 					     "no memory");
4223 			goto out;
4224 		}
4225 		/* Construct the object path for this BSS. */
4226 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
4227 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
4228 			    wpa_s->dbus_new_path, bss->id);
4229 	}
4230 
4231 	success = wpas_dbus_simple_array_property_getter(iter,
4232 							 DBUS_TYPE_OBJECT_PATH,
4233 							 paths, wpa_s->num_bss,
4234 							 error);
4235 
4236 out:
4237 	while (i)
4238 		os_free(paths[--i]);
4239 	os_free(paths);
4240 	return success;
4241 }
4242 
4243 
4244 /**
4245  * wpas_dbus_getter_networks - Get array of networks objects
4246  * @iter: Pointer to incoming dbus message iter
4247  * @error: Location to store error on failure
4248  * @user_data: Function specific data
4249  * Returns: TRUE on success, FALSE on failure
4250  *
4251  * Getter for "Networks" property.
4252  */
wpas_dbus_getter_networks(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4253 dbus_bool_t wpas_dbus_getter_networks(
4254 	const struct wpa_dbus_property_desc *property_desc,
4255 	DBusMessageIter *iter, DBusError *error, void *user_data)
4256 {
4257 	struct wpa_supplicant *wpa_s = user_data;
4258 	struct wpa_ssid *ssid;
4259 	char **paths;
4260 	unsigned int i = 0, num = 0;
4261 	dbus_bool_t success = FALSE;
4262 
4263 	if (!wpa_s->dbus_new_path) {
4264 		dbus_set_error(error, DBUS_ERROR_FAILED,
4265 			       "%s: no D-Bus interface", __func__);
4266 		return FALSE;
4267 	}
4268 
4269 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
4270 		if (!network_is_persistent_group(ssid))
4271 			num++;
4272 
4273 	paths = os_calloc(num, sizeof(char *));
4274 	if (!paths) {
4275 		dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
4276 		return FALSE;
4277 	}
4278 
4279 	/* Loop through configured networks and append object path of each */
4280 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
4281 		if (network_is_persistent_group(ssid))
4282 			continue;
4283 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
4284 		if (paths[i] == NULL) {
4285 			dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
4286 				       "no memory");
4287 			goto out;
4288 		}
4289 
4290 		/* Construct the object path for this network. */
4291 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
4292 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
4293 			    wpa_s->dbus_new_path, ssid->id);
4294 	}
4295 
4296 	success = wpas_dbus_simple_array_property_getter(iter,
4297 							 DBUS_TYPE_OBJECT_PATH,
4298 							 paths, num, error);
4299 
4300 out:
4301 	while (i)
4302 		os_free(paths[--i]);
4303 	os_free(paths);
4304 	return success;
4305 }
4306 
4307 
4308 /**
4309  * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
4310  * @iter: Pointer to incoming dbus message iter
4311  * @error: Location to store error on failure
4312  * @user_data: Function specific data
4313  * Returns: A dbus message containing the PKCS #11 engine path
4314  *
4315  * Getter for "PKCS11EnginePath" property.
4316  */
wpas_dbus_getter_pkcs11_engine_path(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4317 dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(
4318 	const struct wpa_dbus_property_desc *property_desc,
4319 	DBusMessageIter *iter, DBusError *error, void *user_data)
4320 {
4321 	struct wpa_supplicant *wpa_s = user_data;
4322 
4323 	return wpas_dbus_string_property_getter(iter,
4324 						wpa_s->conf->pkcs11_engine_path,
4325 						error);
4326 }
4327 
4328 
4329 /**
4330  * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
4331  * @iter: Pointer to incoming dbus message iter
4332  * @error: Location to store error on failure
4333  * @user_data: Function specific data
4334  * Returns: A dbus message containing the PKCS #11 module path
4335  *
4336  * Getter for "PKCS11ModulePath" property.
4337  */
wpas_dbus_getter_pkcs11_module_path(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4338 dbus_bool_t wpas_dbus_getter_pkcs11_module_path(
4339 	const struct wpa_dbus_property_desc *property_desc,
4340 	DBusMessageIter *iter, DBusError *error, void *user_data)
4341 {
4342 	struct wpa_supplicant *wpa_s = user_data;
4343 
4344 	return wpas_dbus_string_property_getter(iter,
4345 						wpa_s->conf->pkcs11_module_path,
4346 						error);
4347 }
4348 
4349 
4350 /**
4351  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
4352  * @iter: Pointer to incoming dbus message iter
4353  * @error: Location to store error on failure
4354  * @user_data: Function specific data
4355  * Returns: TRUE on success, FALSE on failure
4356  *
4357  * Getter for "Blobs" property.
4358  */
wpas_dbus_getter_blobs(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4359 dbus_bool_t wpas_dbus_getter_blobs(
4360 	const struct wpa_dbus_property_desc *property_desc,
4361 	DBusMessageIter *iter, DBusError *error, void *user_data)
4362 {
4363 	struct wpa_supplicant *wpa_s = user_data;
4364 	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
4365 	struct wpa_config_blob *blob;
4366 
4367 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
4368 					      "a{say}", &variant_iter) ||
4369 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
4370 					      "{say}", &dict_iter)) {
4371 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4372 		return FALSE;
4373 	}
4374 
4375 	blob = wpa_s->conf->blobs;
4376 	while (blob) {
4377 		if (!dbus_message_iter_open_container(&dict_iter,
4378 						      DBUS_TYPE_DICT_ENTRY,
4379 						      NULL, &entry_iter) ||
4380 		    !dbus_message_iter_append_basic(&entry_iter,
4381 						    DBUS_TYPE_STRING,
4382 						    &(blob->name)) ||
4383 		    !dbus_message_iter_open_container(&entry_iter,
4384 						      DBUS_TYPE_ARRAY,
4385 						      DBUS_TYPE_BYTE_AS_STRING,
4386 						      &array_iter) ||
4387 		    !dbus_message_iter_append_fixed_array(&array_iter,
4388 							  DBUS_TYPE_BYTE,
4389 							  &(blob->data),
4390 							  blob->len) ||
4391 		    !dbus_message_iter_close_container(&entry_iter,
4392 						       &array_iter) ||
4393 		    !dbus_message_iter_close_container(&dict_iter,
4394 						       &entry_iter)) {
4395 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4396 					     "no memory");
4397 			return FALSE;
4398 		}
4399 
4400 		blob = blob->next;
4401 	}
4402 
4403 	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
4404 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
4405 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4406 		return FALSE;
4407 	}
4408 
4409 	return TRUE;
4410 }
4411 
4412 
wpas_dbus_getter_iface_global(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4413 dbus_bool_t wpas_dbus_getter_iface_global(
4414 	const struct wpa_dbus_property_desc *property_desc,
4415 	DBusMessageIter *iter, DBusError *error, void *user_data)
4416 {
4417 	struct wpa_supplicant *wpa_s = user_data;
4418 	int ret;
4419 	char buf[250];
4420 	char *p = buf;
4421 
4422 	if (!property_desc->data) {
4423 		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
4424 			       "Unhandled interface property %s",
4425 			       property_desc->dbus_property);
4426 		return FALSE;
4427 	}
4428 
4429 	ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf,
4430 				   sizeof(buf));
4431 	if (ret < 0)
4432 		*p = '\0';
4433 
4434 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p,
4435 						error);
4436 }
4437 
4438 
wpas_dbus_setter_iface_global(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4439 dbus_bool_t wpas_dbus_setter_iface_global(
4440 	const struct wpa_dbus_property_desc *property_desc,
4441 	DBusMessageIter *iter, DBusError *error, void *user_data)
4442 {
4443 	struct wpa_supplicant *wpa_s = user_data;
4444 	const char *new_value = NULL;
4445 	char buf[250];
4446 	size_t combined_len;
4447 	int wpa_sm_param;
4448 	int ret;
4449 
4450 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
4451 					      &new_value))
4452 		return FALSE;
4453 
4454 	combined_len = os_strlen(property_desc->data) + os_strlen(new_value) +
4455 		3;
4456 	if (combined_len >= sizeof(buf)) {
4457 		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
4458 			       "Interface property %s value too large",
4459 			       property_desc->dbus_property);
4460 		return FALSE;
4461 	}
4462 
4463 	if (!new_value[0])
4464 		new_value = "NULL";
4465 
4466 	wpa_sm_param = -1;
4467 	if (os_strcmp(property_desc->data, "dot11RSNAConfigPMKLifetime") == 0)
4468 		wpa_sm_param = RSNA_PMK_LIFETIME;
4469 	else if (os_strcmp(property_desc->data,
4470 			   "dot11RSNAConfigPMKReauthThreshold") == 0)
4471 		wpa_sm_param = RSNA_PMK_REAUTH_THRESHOLD;
4472 	else if (os_strcmp(property_desc->data, "dot11RSNAConfigSATimeout") == 0)
4473 		wpa_sm_param = RSNA_SA_TIMEOUT;
4474 
4475 	if (wpa_sm_param != -1) {
4476 		char *end;
4477 		int val;
4478 
4479 		val = strtol(new_value, &end, 0);
4480 		if (*end) {
4481 			dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
4482 				       "Invalid value for property %s",
4483 				       property_desc->dbus_property);
4484 			return FALSE;
4485 		}
4486 
4487 		if (wpa_sm_set_param(wpa_s->wpa, wpa_sm_param, val)) {
4488 			dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
4489 				       "Failed to apply interface property %s",
4490 				       property_desc->dbus_property);
4491 			return FALSE;
4492 		}
4493 	}
4494 
4495 	ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data,
4496 			  new_value);
4497 	if (os_snprintf_error(combined_len, ret)) {
4498 		dbus_set_error(error,  WPAS_DBUS_ERROR_UNKNOWN_ERROR,
4499 			       "Failed to construct new interface property %s",
4500 			       property_desc->dbus_property);
4501 		return FALSE;
4502 	}
4503 
4504 	ret = wpa_config_process_global(wpa_s->conf, buf, -1);
4505 	if (ret < 0) {
4506 		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
4507 			       "Failed to set interface property %s",
4508 			       property_desc->dbus_property);
4509 		return FALSE;
4510 	} else if (ret == 0) {
4511 		wpa_supplicant_update_config(wpa_s);
4512 	}
4513 	return TRUE;
4514 }
4515 
4516 
4517 /**
4518  * wpas_dbus_getter_stas - Get connected stations for an interface
4519  * @iter: Pointer to incoming dbus message iter
4520  * @error: Location to store error on failure
4521  * @user_data: Function specific data
4522  * Returns: a list of stations
4523  *
4524  * Getter for "Stations" property.
4525  */
wpas_dbus_getter_stas(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4526 dbus_bool_t wpas_dbus_getter_stas(
4527 	const struct wpa_dbus_property_desc *property_desc,
4528 	DBusMessageIter *iter, DBusError *error, void *user_data)
4529 {
4530 	struct wpa_supplicant *wpa_s = user_data;
4531 	struct sta_info *sta = NULL;
4532 	char **paths = NULL;
4533 	unsigned int i = 0, num = 0;
4534 	dbus_bool_t success = FALSE;
4535 
4536 	if (!wpa_s->dbus_new_path) {
4537 		dbus_set_error(error, DBUS_ERROR_FAILED,
4538 			       "%s: no D-Bus interface", __func__);
4539 		return FALSE;
4540 	}
4541 
4542 #ifdef CONFIG_AP
4543 	if (wpa_s->ap_iface) {
4544 		struct hostapd_data *hapd;
4545 
4546 		hapd = wpa_s->ap_iface->bss[0];
4547 		sta = hapd->sta_list;
4548 		num = hapd->num_sta;
4549 	}
4550 #endif /* CONFIG_AP */
4551 
4552 	paths = os_calloc(num, sizeof(char *));
4553 	if (!paths) {
4554 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4555 		return FALSE;
4556 	}
4557 
4558 	/* Loop through scan results and append each result's object path */
4559 	for (; sta; sta = sta->next) {
4560 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
4561 		if (!paths[i]) {
4562 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4563 					     "no memory");
4564 			goto out;
4565 		}
4566 		/* Construct the object path for this BSS. */
4567 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
4568 			    "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
4569 			    wpa_s->dbus_new_path, MAC2STR(sta->addr));
4570 	}
4571 
4572 	success = wpas_dbus_simple_array_property_getter(iter,
4573 							 DBUS_TYPE_OBJECT_PATH,
4574 							 paths, num,
4575 							 error);
4576 
4577 out:
4578 	while (i)
4579 		os_free(paths[--i]);
4580 	os_free(paths);
4581 	return success;
4582 }
4583 
4584 
4585 /**
4586  * wpas_dbus_setter_mac_address_randomization_mask - Set masks used for
4587  * MAC address randomization
4588  * @iter: Pointer to incoming dbus message iter
4589  * @error: Location to store error on failure
4590  * @user_data: Function specific data
4591  * Returns: TRUE on success, FALSE on failure
4592  *
4593  * Setter for "MACAddressRandomizationMask" property.
4594  */
wpas_dbus_setter_mac_address_randomization_mask(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4595 dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
4596 	const struct wpa_dbus_property_desc *property_desc,
4597 	DBusMessageIter *iter, DBusError *error, void *user_data)
4598 {
4599 	struct wpa_supplicant *wpa_s = user_data;
4600 	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
4601 	const char *key;
4602 	unsigned int rand_type = 0;
4603 	const u8 *mask;
4604 	int mask_len;
4605 	unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
4606 
4607 	dbus_message_iter_recurse(iter, &variant_iter);
4608 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) {
4609 		dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
4610 				     "invalid message format");
4611 		return FALSE;
4612 	}
4613 	dbus_message_iter_recurse(&variant_iter, &dict_iter);
4614 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
4615 	       DBUS_TYPE_DICT_ENTRY) {
4616 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
4617 		if (dbus_message_iter_get_arg_type(&entry_iter) !=
4618 		    DBUS_TYPE_STRING) {
4619 			dbus_set_error(error, DBUS_ERROR_FAILED,
4620 				       "%s: key not a string", __func__);
4621 			return FALSE;
4622 		}
4623 		dbus_message_iter_get_basic(&entry_iter, &key);
4624 		dbus_message_iter_next(&entry_iter);
4625 		if (dbus_message_iter_get_arg_type(&entry_iter) !=
4626 		    DBUS_TYPE_ARRAY ||
4627 		    dbus_message_iter_get_element_type(&entry_iter) !=
4628 		    DBUS_TYPE_BYTE) {
4629 			dbus_set_error(error, DBUS_ERROR_FAILED,
4630 				       "%s: mask was not a byte array",
4631 				       __func__);
4632 			return FALSE;
4633 		}
4634 		dbus_message_iter_recurse(&entry_iter, &array_iter);
4635 		dbus_message_iter_get_fixed_array(&array_iter, &mask,
4636 						  &mask_len);
4637 
4638 		if (os_strcmp(key, "scan") == 0) {
4639 			rand_type = MAC_ADDR_RAND_SCAN;
4640 		} else if (os_strcmp(key, "sched_scan") == 0) {
4641 			rand_type = MAC_ADDR_RAND_SCHED_SCAN;
4642 		} else if (os_strcmp(key, "pno") == 0) {
4643 			rand_type = MAC_ADDR_RAND_PNO;
4644 		} else {
4645 			dbus_set_error(error, DBUS_ERROR_FAILED,
4646 				       "%s: bad scan type \"%s\"",
4647 				       __func__, key);
4648 			return FALSE;
4649 		}
4650 
4651 		if (mask_len != ETH_ALEN) {
4652 			dbus_set_error(error, DBUS_ERROR_FAILED,
4653 				       "%s: malformed MAC mask given",
4654 				       __func__);
4655 			return FALSE;
4656 		}
4657 
4658 		if (wpas_enable_mac_addr_randomization(
4659 			    wpa_s, rand_type, wpa_s->perm_addr, mask)) {
4660 			dbus_set_error(error, DBUS_ERROR_FAILED,
4661 				       "%s: failed to set up MAC address randomization for %s",
4662 				       __func__, key);
4663 			return FALSE;
4664 		}
4665 
4666 		wpa_printf(MSG_DEBUG,
4667 			   "%s: Enabled MAC address randomization for %s with mask: "
4668 			   MACSTR, wpa_s->ifname, key, MAC2STR(mask));
4669 		rand_types_to_disable &= ~rand_type;
4670 		dbus_message_iter_next(&dict_iter);
4671 	}
4672 
4673 	if (rand_types_to_disable &&
4674 	    wpas_disable_mac_addr_randomization(wpa_s, rand_types_to_disable)) {
4675 		dbus_set_error(error, DBUS_ERROR_FAILED,
4676 			       "%s: failed to disable MAC address randomization",
4677 			       __func__);
4678 		return FALSE;
4679 	}
4680 
4681 	return TRUE;
4682 }
4683 
4684 
wpas_dbus_getter_mac_address_randomization_mask(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4685 dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
4686 	const struct wpa_dbus_property_desc *property_desc,
4687 	DBusMessageIter *iter, DBusError *error, void *user_data)
4688 {
4689 	struct wpa_supplicant *wpa_s = user_data;
4690 	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
4691 	unsigned int i;
4692 	u8 mask_buf[ETH_ALEN];
4693 	/* Read docs on dbus_message_iter_append_fixed_array() for why this
4694 	 * is necessary... */
4695 	u8 *mask = mask_buf;
4696 	static const struct {
4697 		const char *key;
4698 		unsigned int type;
4699 	} types[] = {
4700 		{ "scan", MAC_ADDR_RAND_SCAN },
4701 		{ "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
4702 		{ "pno", MAC_ADDR_RAND_PNO }
4703 	};
4704 
4705 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
4706 					      "a{say}", &variant_iter) ||
4707 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
4708 					      "{say}", &dict_iter)) {
4709 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4710 		return FALSE;
4711 	}
4712 
4713 	for (i = 0; i < ARRAY_SIZE(types); i++) {
4714 		if (wpas_mac_addr_rand_scan_get_mask(wpa_s, types[i].type,
4715 						     mask))
4716 			continue;
4717 
4718 		if (!dbus_message_iter_open_container(&dict_iter,
4719 						      DBUS_TYPE_DICT_ENTRY,
4720 						      NULL, &entry_iter) ||
4721 		    !dbus_message_iter_append_basic(&entry_iter,
4722 						    DBUS_TYPE_STRING,
4723 						    &types[i].key) ||
4724 		    !dbus_message_iter_open_container(&entry_iter,
4725 						      DBUS_TYPE_ARRAY,
4726 						      DBUS_TYPE_BYTE_AS_STRING,
4727 						      &array_iter) ||
4728 		    !dbus_message_iter_append_fixed_array(&array_iter,
4729 							  DBUS_TYPE_BYTE,
4730 							  &mask,
4731 							  ETH_ALEN) ||
4732 		    !dbus_message_iter_close_container(&entry_iter,
4733 						       &array_iter) ||
4734 		    !dbus_message_iter_close_container(&dict_iter,
4735 						       &entry_iter)) {
4736 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4737 					     "no memory");
4738 			return FALSE;
4739 		}
4740 	}
4741 
4742 	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
4743 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
4744 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4745 		return FALSE;
4746 	}
4747 
4748 	return TRUE;
4749 }
4750 
4751 
4752 /**
4753  * wpas_dbus_getter_mac_address - Get MAC address of an interface
4754  * @iter: Pointer to incoming dbus message iter
4755  * @error: Location to store error on failure
4756  * @user_data: Function specific data
4757  * Returns: a list of stations
4758  *
4759  * Getter for "MACAddress" property.
4760  */
wpas_dbus_getter_mac_address(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4761 dbus_bool_t wpas_dbus_getter_mac_address(
4762 	const struct wpa_dbus_property_desc *property_desc,
4763 	DBusMessageIter *iter, DBusError *error, void *user_data)
4764 {
4765 	struct wpa_supplicant *wpa_s = user_data;
4766 
4767 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4768 						      wpa_s->own_addr, ETH_ALEN,
4769 						      error);
4770 }
4771 
4772 
4773 /**
4774  * wpas_dbus_getter_sta_address - Return the address of a connected station
4775  * @iter: Pointer to incoming dbus message iter
4776  * @error: Location to store error on failure
4777  * @user_data: Function specific data
4778  * Returns: TRUE on success, FALSE on failure
4779  *
4780  * Getter for "Address" property.
4781  */
wpas_dbus_getter_sta_address(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4782 dbus_bool_t wpas_dbus_getter_sta_address(
4783 	const struct wpa_dbus_property_desc *property_desc,
4784 	DBusMessageIter *iter, DBusError *error, void *user_data)
4785 {
4786 #ifdef CONFIG_AP
4787 	struct sta_handler_args *args = user_data;
4788 	struct sta_info *sta;
4789 
4790 	sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4791 	if (!sta)
4792 		return FALSE;
4793 
4794 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4795 						      sta->addr, ETH_ALEN,
4796 						      error);
4797 #else /* CONFIG_AP */
4798     return FALSE;
4799 #endif /* CONFIG_AP */
4800 }
4801 
4802 
4803 /**
4804  * wpas_dbus_getter_sta_aid - Return the AID of a connected station
4805  * @iter: Pointer to incoming dbus message iter
4806  * @error: Location to store error on failure
4807  * @user_data: Function specific data
4808  * Returns: TRUE on success, FALSE on failure
4809  *
4810  * Getter for "AID" property.
4811  */
wpas_dbus_getter_sta_aid(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4812 dbus_bool_t wpas_dbus_getter_sta_aid(
4813 	const struct wpa_dbus_property_desc *property_desc,
4814 	DBusMessageIter *iter, DBusError *error, void *user_data)
4815 {
4816 #ifdef CONFIG_AP
4817 	struct sta_handler_args *args = user_data;
4818 	struct sta_info *sta;
4819 
4820 	sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4821 	if (!sta)
4822 		return FALSE;
4823 
4824 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4825 						&sta->aid,
4826 						error);
4827 #else /* CONFIG_AP */
4828     return FALSE;
4829 #endif /* CONFIG_AP */
4830 }
4831 
4832 
4833 /**
4834  * wpas_dbus_getter_sta_caps - Return the capabilities of a station
4835  * @iter: Pointer to incoming dbus message iter
4836  * @error: Location to store error on failure
4837  * @user_data: Function specific data
4838  * Returns: TRUE on success, FALSE on failure
4839  *
4840  * Getter for "Capabilities" property.
4841  */
wpas_dbus_getter_sta_caps(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4842 dbus_bool_t wpas_dbus_getter_sta_caps(
4843 	const struct wpa_dbus_property_desc *property_desc,
4844 	DBusMessageIter *iter, DBusError *error, void *user_data)
4845 {
4846 #ifdef CONFIG_AP
4847 	struct sta_handler_args *args = user_data;
4848 	struct sta_info *sta;
4849 
4850 	sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4851 	if (!sta)
4852 		return FALSE;
4853 
4854 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4855 						&sta->capability,
4856 						error);
4857 #else /* CONFIG_AP */
4858     return FALSE;
4859 #endif /* CONFIG_AP */
4860 }
4861 
4862 
4863 /**
4864  * wpas_dbus_getter_rx_packets - Return the received packets for a station
4865  * @iter: Pointer to incoming dbus message iter
4866  * @error: Location to store error on failure
4867  * @user_data: Function specific data
4868  * Returns: TRUE on success, FALSE on failure
4869  *
4870  * Getter for "RxPackets" property.
4871  */
wpas_dbus_getter_sta_rx_packets(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4872 dbus_bool_t wpas_dbus_getter_sta_rx_packets(
4873 	const struct wpa_dbus_property_desc *property_desc,
4874 	DBusMessageIter *iter, DBusError *error, void *user_data)
4875 {
4876 #ifdef CONFIG_AP
4877 	struct sta_handler_args *args = user_data;
4878 	struct sta_info *sta;
4879 	struct hostap_sta_driver_data data;
4880 	struct hostapd_data *hapd;
4881 
4882 	if (!args->wpa_s->ap_iface)
4883 		return FALSE;
4884 
4885 	hapd = args->wpa_s->ap_iface->bss[0];
4886 	sta = ap_get_sta(hapd, args->sta);
4887 	if (!sta)
4888 		return FALSE;
4889 
4890 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4891 		return FALSE;
4892 
4893 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4894 						&data.rx_packets,
4895 						error);
4896 #else /* CONFIG_AP */
4897     return FALSE;
4898 #endif /* CONFIG_AP */
4899 }
4900 
4901 
4902 /**
4903  * wpas_dbus_getter_tx_packets - Return the transmitted packets for a station
4904  * @iter: Pointer to incoming dbus message iter
4905  * @error: Location to store error on failure
4906  * @user_data: Function specific data
4907  * Returns: TRUE on success, FALSE on failure
4908  *
4909  * Getter for "TxPackets" property.
4910  */
wpas_dbus_getter_sta_tx_packets(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4911 dbus_bool_t wpas_dbus_getter_sta_tx_packets(
4912 	const struct wpa_dbus_property_desc *property_desc,
4913 	DBusMessageIter *iter, DBusError *error, void *user_data)
4914 {
4915 #ifdef CONFIG_AP
4916 	struct sta_handler_args *args = user_data;
4917 	struct sta_info *sta;
4918 	struct hostap_sta_driver_data data;
4919 	struct hostapd_data *hapd;
4920 
4921 	if (!args->wpa_s->ap_iface)
4922 		return FALSE;
4923 
4924 	hapd = args->wpa_s->ap_iface->bss[0];
4925 	sta = ap_get_sta(hapd, args->sta);
4926 	if (!sta)
4927 		return FALSE;
4928 
4929 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4930 		return FALSE;
4931 
4932 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4933 						&data.tx_packets,
4934 						error);
4935 #else /* CONFIG_AP */
4936     return FALSE;
4937 #endif /* CONFIG_AP */
4938 }
4939 
4940 
4941 /**
4942  * wpas_dbus_getter_tx_bytes - Return the transmitted bytes for a station
4943  * @iter: Pointer to incoming dbus message iter
4944  * @error: Location to store error on failure
4945  * @user_data: Function specific data
4946  * Returns: TRUE on success, FALSE on failure
4947  *
4948  * Getter for "TxBytes" property.
4949  */
wpas_dbus_getter_sta_tx_bytes(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4950 dbus_bool_t wpas_dbus_getter_sta_tx_bytes(
4951 	const struct wpa_dbus_property_desc *property_desc,
4952 	DBusMessageIter *iter, DBusError *error, void *user_data)
4953 {
4954 #ifdef CONFIG_AP
4955 	struct sta_handler_args *args = user_data;
4956 	struct sta_info *sta;
4957 	struct hostap_sta_driver_data data;
4958 	struct hostapd_data *hapd;
4959 
4960 	if (!args->wpa_s->ap_iface)
4961 		return FALSE;
4962 
4963 	hapd = args->wpa_s->ap_iface->bss[0];
4964 	sta = ap_get_sta(hapd, args->sta);
4965 	if (!sta)
4966 		return FALSE;
4967 
4968 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4969 		return FALSE;
4970 
4971 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4972 						&data.tx_bytes,
4973 						error);
4974 #else /* CONFIG_AP */
4975     return FALSE;
4976 #endif /* CONFIG_AP */
4977 }
4978 
4979 
4980 /**
4981  * wpas_dbus_getter_rx_bytes - Return the received bytes for a station
4982  * @iter: Pointer to incoming dbus message iter
4983  * @error: Location to store error on failure
4984  * @user_data: Function specific data
4985  * Returns: TRUE on success, FALSE on failure
4986  *
4987  * Getter for "RxBytes" property.
4988  */
wpas_dbus_getter_sta_rx_bytes(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4989 dbus_bool_t wpas_dbus_getter_sta_rx_bytes(
4990 	const struct wpa_dbus_property_desc *property_desc,
4991 	DBusMessageIter *iter, DBusError *error, void *user_data)
4992 {
4993 #ifdef CONFIG_AP
4994 	struct sta_handler_args *args = user_data;
4995 	struct sta_info *sta;
4996 	struct hostap_sta_driver_data data;
4997 	struct hostapd_data *hapd;
4998 
4999 	if (!args->wpa_s->ap_iface)
5000 		return FALSE;
5001 
5002 	hapd = args->wpa_s->ap_iface->bss[0];
5003 	sta = ap_get_sta(hapd, args->sta);
5004 	if (!sta)
5005 		return FALSE;
5006 
5007 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
5008 		return FALSE;
5009 
5010 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
5011 						&data.rx_bytes,
5012 						error);
5013 #else /* CONFIG_AP */
5014     return FALSE;
5015 #endif /* CONFIG_AP */
5016 }
5017 
5018 
get_bss_helper(struct bss_handler_args * args,DBusError * error,const char * func_name)5019 static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
5020 				       DBusError *error, const char *func_name)
5021 {
5022 	struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
5023 
5024 	if (!res) {
5025 		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
5026 			   func_name, args->id);
5027 		dbus_set_error(error, DBUS_ERROR_FAILED,
5028 			       "%s: BSS %d not found",
5029 			       func_name, args->id);
5030 	}
5031 
5032 	return res;
5033 }
5034 
5035 
5036 /**
5037  * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
5038  * @iter: Pointer to incoming dbus message iter
5039  * @error: Location to store error on failure
5040  * @user_data: Function specific data
5041  * Returns: TRUE on success, FALSE on failure
5042  *
5043  * Getter for "BSSID" property.
5044  */
wpas_dbus_getter_bss_bssid(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5045 dbus_bool_t wpas_dbus_getter_bss_bssid(
5046 	const struct wpa_dbus_property_desc *property_desc,
5047 	DBusMessageIter *iter, DBusError *error, void *user_data)
5048 {
5049 	struct bss_handler_args *args = user_data;
5050 	struct wpa_bss *res;
5051 
5052 	res = get_bss_helper(args, error, __func__);
5053 	if (!res)
5054 		return FALSE;
5055 
5056 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
5057 						      res->bssid, ETH_ALEN,
5058 						      error);
5059 }
5060 
5061 
5062 /**
5063  * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
5064  * @iter: Pointer to incoming dbus message iter
5065  * @error: Location to store error on failure
5066  * @user_data: Function specific data
5067  * Returns: TRUE on success, FALSE on failure
5068  *
5069  * Getter for "SSID" property.
5070  */
wpas_dbus_getter_bss_ssid(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5071 dbus_bool_t wpas_dbus_getter_bss_ssid(
5072 	const struct wpa_dbus_property_desc *property_desc,
5073 	DBusMessageIter *iter, DBusError *error, void *user_data)
5074 {
5075 	struct bss_handler_args *args = user_data;
5076 	struct wpa_bss *res;
5077 
5078 	res = get_bss_helper(args, error, __func__);
5079 	if (!res)
5080 		return FALSE;
5081 
5082 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
5083 						      res->ssid, res->ssid_len,
5084 						      error);
5085 }
5086 
5087 
5088 /**
5089  * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
5090  * @iter: Pointer to incoming dbus message iter
5091  * @error: Location to store error on failure
5092  * @user_data: Function specific data
5093  * Returns: TRUE on success, FALSE on failure
5094  *
5095  * Getter for "Privacy" property.
5096  */
wpas_dbus_getter_bss_privacy(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5097 dbus_bool_t wpas_dbus_getter_bss_privacy(
5098 	const struct wpa_dbus_property_desc *property_desc,
5099 	DBusMessageIter *iter, DBusError *error, void *user_data)
5100 {
5101 	struct bss_handler_args *args = user_data;
5102 	struct wpa_bss *res;
5103 	dbus_bool_t privacy;
5104 
5105 	res = get_bss_helper(args, error, __func__);
5106 	if (!res)
5107 		return FALSE;
5108 
5109 	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
5110 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
5111 						&privacy, error);
5112 }
5113 
5114 
5115 /**
5116  * wpas_dbus_getter_bss_mode - Return the mode of a BSS
5117  * @iter: Pointer to incoming dbus message iter
5118  * @error: Location to store error on failure
5119  * @user_data: Function specific data
5120  * Returns: TRUE on success, FALSE on failure
5121  *
5122  * Getter for "Mode" property.
5123  */
wpas_dbus_getter_bss_mode(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5124 dbus_bool_t wpas_dbus_getter_bss_mode(
5125 	const struct wpa_dbus_property_desc *property_desc,
5126 	DBusMessageIter *iter, DBusError *error, void *user_data)
5127 {
5128 	struct bss_handler_args *args = user_data;
5129 	struct wpa_bss *res;
5130 	const char *mode;
5131 	const u8 *mesh;
5132 
5133 	res = get_bss_helper(args, error, __func__);
5134 	if (!res)
5135 		return FALSE;
5136 	if (bss_is_dmg(res)) {
5137 		switch (res->caps & IEEE80211_CAP_DMG_MASK) {
5138 		case IEEE80211_CAP_DMG_PBSS:
5139 		case IEEE80211_CAP_DMG_IBSS:
5140 			mode = "ad-hoc";
5141 			break;
5142 		case IEEE80211_CAP_DMG_AP:
5143 			mode = "infrastructure";
5144 			break;
5145 		default:
5146 			mode = "";
5147 			break;
5148 		}
5149 	} else {
5150 		mesh = wpa_bss_get_ie(res, WLAN_EID_MESH_ID);
5151 		if (mesh)
5152 			mode = "mesh";
5153 		else if (res->caps & IEEE80211_CAP_IBSS)
5154 			mode = "ad-hoc";
5155 		else
5156 			mode = "infrastructure";
5157 	}
5158 
5159 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
5160 						&mode, error);
5161 }
5162 
5163 
5164 /**
5165  * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
5166  * @iter: Pointer to incoming dbus message iter
5167  * @error: Location to store error on failure
5168  * @user_data: Function specific data
5169  * Returns: TRUE on success, FALSE on failure
5170  *
5171  * Getter for "Level" property.
5172  */
wpas_dbus_getter_bss_signal(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5173 dbus_bool_t wpas_dbus_getter_bss_signal(
5174 	const struct wpa_dbus_property_desc *property_desc,
5175 	DBusMessageIter *iter, DBusError *error, void *user_data)
5176 {
5177 	struct bss_handler_args *args = user_data;
5178 	struct wpa_bss *res;
5179 	s16 level;
5180 
5181 	res = get_bss_helper(args, error, __func__);
5182 	if (!res)
5183 		return FALSE;
5184 
5185 	level = (s16) res->level;
5186 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
5187 						&level, error);
5188 }
5189 
5190 
5191 /**
5192  * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
5193  * @iter: Pointer to incoming dbus message iter
5194  * @error: Location to store error on failure
5195  * @user_data: Function specific data
5196  * Returns: TRUE on success, FALSE on failure
5197  *
5198  * Getter for "Frequency" property.
5199  */
wpas_dbus_getter_bss_frequency(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5200 dbus_bool_t wpas_dbus_getter_bss_frequency(
5201 	const struct wpa_dbus_property_desc *property_desc,
5202 	DBusMessageIter *iter, DBusError *error, void *user_data)
5203 {
5204 	struct bss_handler_args *args = user_data;
5205 	struct wpa_bss *res;
5206 	u16 freq;
5207 
5208 	res = get_bss_helper(args, error, __func__);
5209 	if (!res)
5210 		return FALSE;
5211 
5212 	freq = (u16) res->freq;
5213 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
5214 						&freq, error);
5215 }
5216 
5217 
cmp_u8s_desc(const void * a,const void * b)5218 static int cmp_u8s_desc(const void *a, const void *b)
5219 {
5220 	return (*(u8 *) b - *(u8 *) a);
5221 }
5222 
5223 
5224 /**
5225  * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
5226  * @iter: Pointer to incoming dbus message iter
5227  * @error: Location to store error on failure
5228  * @user_data: Function specific data
5229  * Returns: TRUE on success, FALSE on failure
5230  *
5231  * Getter for "Rates" property.
5232  */
wpas_dbus_getter_bss_rates(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5233 dbus_bool_t wpas_dbus_getter_bss_rates(
5234 	const struct wpa_dbus_property_desc *property_desc,
5235 	DBusMessageIter *iter, DBusError *error, void *user_data)
5236 {
5237 	struct bss_handler_args *args = user_data;
5238 	struct wpa_bss *res;
5239 	u8 *ie_rates = NULL;
5240 	u32 *real_rates;
5241 	int rates_num, i;
5242 	dbus_bool_t success = FALSE;
5243 
5244 	res = get_bss_helper(args, error, __func__);
5245 	if (!res)
5246 		return FALSE;
5247 
5248 	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
5249 	if (rates_num < 0)
5250 		return FALSE;
5251 
5252 	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
5253 
5254 	real_rates = os_malloc(sizeof(u32) * rates_num);
5255 	if (!real_rates) {
5256 		os_free(ie_rates);
5257 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5258 		return FALSE;
5259 	}
5260 
5261 	for (i = 0; i < rates_num; i++)
5262 		real_rates[i] = ie_rates[i] * 500000;
5263 
5264 	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
5265 							 real_rates, rates_num,
5266 							 error);
5267 
5268 	os_free(ie_rates);
5269 	os_free(real_rates);
5270 	return success;
5271 }
5272 
5273 
wpas_dbus_get_bss_security_prop(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,struct wpa_ie_data * ie_data,DBusError * error)5274 static dbus_bool_t wpas_dbus_get_bss_security_prop(
5275 	const struct wpa_dbus_property_desc *property_desc,
5276 	DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error)
5277 {
5278 	DBusMessageIter iter_dict, variant_iter;
5279 	const char *group;
5280 	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
5281 	const char *key_mgmt[18]; /* max 18 key managements may be supported */
5282 	int n;
5283 
5284 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
5285 					      "a{sv}", &variant_iter))
5286 		goto nomem;
5287 
5288 	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
5289 		goto nomem;
5290 
5291 	/*
5292 	 * KeyMgmt
5293 	 *
5294 	 * When adding a new entry here, please take care to extend key_mgmt[]
5295 	 * and keep documentation in doc/dbus.doxygen up to date.
5296 	 */
5297 	n = 0;
5298 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
5299 		key_mgmt[n++] = "wpa-psk";
5300 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
5301 		key_mgmt[n++] = "wpa-ft-psk";
5302 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
5303 		key_mgmt[n++] = "wpa-psk-sha256";
5304 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
5305 		key_mgmt[n++] = "wpa-eap";
5306 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
5307 		key_mgmt[n++] = "wpa-ft-eap";
5308 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
5309 		key_mgmt[n++] = "wpa-eap-sha256";
5310 #ifdef CONFIG_SUITEB
5311 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
5312 		key_mgmt[n++] = "wpa-eap-suite-b";
5313 #endif /* CONFIG_SUITEB */
5314 #ifdef CONFIG_SUITEB192
5315 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
5316 		key_mgmt[n++] = "wpa-eap-suite-b-192";
5317 #endif /* CONFIG_SUITEB192 */
5318 #ifdef CONFIG_FILS
5319 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
5320 		key_mgmt[n++] = "wpa-fils-sha256";
5321 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
5322 		key_mgmt[n++] = "wpa-fils-sha384";
5323 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
5324 		key_mgmt[n++] = "wpa-ft-fils-sha256";
5325 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
5326 		key_mgmt[n++] = "wpa-ft-fils-sha384";
5327 #endif /* CONFIG_FILS */
5328 #ifdef CONFIG_SAE
5329 	if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE)
5330 		key_mgmt[n++] = "sae";
5331 	if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY)
5332 		key_mgmt[n++] = "sae-ext-key";
5333 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
5334 		key_mgmt[n++] = "ft-sae";
5335 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
5336 		key_mgmt[n++] = "ft-sae-ext-key";
5337 #endif /* CONFIG_SAE */
5338 #ifdef CONFIG_OWE
5339 	if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE)
5340 		key_mgmt[n++] = "owe";
5341 #endif /* CONFIG_OWE */
5342 	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
5343 		key_mgmt[n++] = "wpa-none";
5344 
5345 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
5346 					       key_mgmt, n))
5347 		goto nomem;
5348 
5349 	/* Group */
5350 	switch (ie_data->group_cipher) {
5351 #ifdef CONFIG_WEP
5352 	case WPA_CIPHER_WEP40:
5353 		group = "wep40";
5354 		break;
5355 	case WPA_CIPHER_WEP104:
5356 		group = "wep104";
5357 		break;
5358 #endif /* CONFIG_WEP */
5359 #ifndef CONFIG_NO_TKIP
5360 	case WPA_CIPHER_TKIP:
5361 		group = "tkip";
5362 		break;
5363 #endif /* CONFIG_NO_TKIP */
5364 	case WPA_CIPHER_CCMP:
5365 		group = "ccmp";
5366 		break;
5367 	case WPA_CIPHER_GCMP:
5368 		group = "gcmp";
5369 		break;
5370 	case WPA_CIPHER_CCMP_256:
5371 		group = "ccmp-256";
5372 		break;
5373 	case WPA_CIPHER_GCMP_256:
5374 		group = "gcmp-256";
5375 		break;
5376 	default:
5377 		group = "";
5378 		break;
5379 	}
5380 
5381 	if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
5382 		goto nomem;
5383 
5384 	/* Pairwise */
5385 	n = 0;
5386 #ifndef CONFIG_NO_TKIP
5387 	if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
5388 		pairwise[n++] = "tkip";
5389 #endif /* CONFIG_NO_TKIP */
5390 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
5391 		pairwise[n++] = "ccmp";
5392 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
5393 		pairwise[n++] = "gcmp";
5394 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
5395 		pairwise[n++] = "ccmp-256";
5396 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
5397 		pairwise[n++] = "gcmp-256";
5398 
5399 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
5400 					       pairwise, n))
5401 		goto nomem;
5402 
5403 	/* Management group (RSN only) */
5404 	if (ie_data->proto == WPA_PROTO_RSN) {
5405 		switch (ie_data->mgmt_group_cipher) {
5406 		case WPA_CIPHER_AES_128_CMAC:
5407 			group = "aes128cmac";
5408 			break;
5409 		default:
5410 			group = "";
5411 			break;
5412 		}
5413 
5414 		if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
5415 						 group))
5416 			goto nomem;
5417 	}
5418 
5419 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
5420 	    !dbus_message_iter_close_container(iter, &variant_iter))
5421 		goto nomem;
5422 
5423 	return TRUE;
5424 
5425 nomem:
5426 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5427 	return FALSE;
5428 }
5429 
5430 
5431 /**
5432  * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
5433  * @iter: Pointer to incoming dbus message iter
5434  * @error: Location to store error on failure
5435  * @user_data: Function specific data
5436  * Returns: TRUE on success, FALSE on failure
5437  *
5438  * Getter for "WPA" property.
5439  */
wpas_dbus_getter_bss_wpa(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5440 dbus_bool_t wpas_dbus_getter_bss_wpa(
5441 	const struct wpa_dbus_property_desc *property_desc,
5442 	DBusMessageIter *iter, DBusError *error, void *user_data)
5443 {
5444 	struct bss_handler_args *args = user_data;
5445 	struct wpa_bss *res;
5446 	struct wpa_ie_data wpa_data;
5447 	const u8 *ie;
5448 
5449 	res = get_bss_helper(args, error, __func__);
5450 	if (!res)
5451 		return FALSE;
5452 
5453 	os_memset(&wpa_data, 0, sizeof(wpa_data));
5454 	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
5455 	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
5456 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
5457 				     "failed to parse WPA IE");
5458 		return FALSE;
5459 	}
5460 
5461 	return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
5462 }
5463 
5464 
5465 /**
5466  * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
5467  * @iter: Pointer to incoming dbus message iter
5468  * @error: Location to store error on failure
5469  * @user_data: Function specific data
5470  * Returns: TRUE on success, FALSE on failure
5471  *
5472  * Getter for "RSN" property.
5473  */
wpas_dbus_getter_bss_rsn(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5474 dbus_bool_t wpas_dbus_getter_bss_rsn(
5475 	const struct wpa_dbus_property_desc *property_desc,
5476 	DBusMessageIter *iter, DBusError *error, void *user_data)
5477 {
5478 	struct bss_handler_args *args = user_data;
5479 	struct wpa_bss *res;
5480 	struct wpa_ie_data wpa_data;
5481 	const u8 *ie;
5482 
5483 	res = get_bss_helper(args, error, __func__);
5484 	if (!res)
5485 		return FALSE;
5486 
5487 	os_memset(&wpa_data, 0, sizeof(wpa_data));
5488 	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
5489 	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
5490 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
5491 				     "failed to parse RSN IE");
5492 		return FALSE;
5493 	}
5494 
5495 	return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
5496 }
5497 
5498 
5499 /**
5500  * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
5501  * @iter: Pointer to incoming dbus message iter
5502  * @error: Location to store error on failure
5503  * @user_data: Function specific data
5504  * Returns: TRUE on success, FALSE on failure
5505  *
5506  * Getter for "WPS" property.
5507  */
wpas_dbus_getter_bss_wps(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5508 dbus_bool_t wpas_dbus_getter_bss_wps(
5509 	const struct wpa_dbus_property_desc *property_desc,
5510 	DBusMessageIter *iter, DBusError *error, void *user_data)
5511 {
5512 	struct bss_handler_args *args = user_data;
5513 	struct wpa_bss *res;
5514 #ifdef CONFIG_WPS
5515 	struct wpabuf *wps_ie;
5516 #endif /* CONFIG_WPS */
5517 	DBusMessageIter iter_dict, variant_iter;
5518 	int wps_support = 0;
5519 	const char *type = "";
5520 
5521 	res = get_bss_helper(args, error, __func__);
5522 	if (!res)
5523 		return FALSE;
5524 
5525 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
5526 					      "a{sv}", &variant_iter) ||
5527 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
5528 		goto nomem;
5529 
5530 #ifdef CONFIG_WPS
5531 	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
5532 	if (wps_ie) {
5533 		wps_support = 1;
5534 		if (wps_is_selected_pbc_registrar(wps_ie))
5535 			type = "pbc";
5536 		else if (wps_is_selected_pin_registrar(wps_ie))
5537 			type = "pin";
5538 
5539 		wpabuf_free(wps_ie);
5540 	}
5541 #endif /* CONFIG_WPS */
5542 
5543 	if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) ||
5544 	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
5545 	    !dbus_message_iter_close_container(iter, &variant_iter))
5546 		goto nomem;
5547 
5548 	return TRUE;
5549 
5550 nomem:
5551 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5552 	return FALSE;
5553 }
5554 
5555 
5556 /**
5557  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
5558  * @iter: Pointer to incoming dbus message iter
5559  * @error: Location to store error on failure
5560  * @user_data: Function specific data
5561  * Returns: TRUE on success, FALSE on failure
5562  *
5563  * Getter for "IEs" property.
5564  */
wpas_dbus_getter_bss_ies(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5565 dbus_bool_t wpas_dbus_getter_bss_ies(
5566 	const struct wpa_dbus_property_desc *property_desc,
5567 	DBusMessageIter *iter, DBusError *error, void *user_data)
5568 {
5569 	struct bss_handler_args *args = user_data;
5570 	struct wpa_bss *res;
5571 
5572 	res = get_bss_helper(args, error, __func__);
5573 	if (!res)
5574 		return FALSE;
5575 
5576 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
5577 						      wpa_bss_ie_ptr(res),
5578 						      res->ie_len, error);
5579 }
5580 
5581 
5582 /**
5583  * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
5584  * @iter: Pointer to incoming dbus message iter
5585  * @error: Location to store error on failure
5586  * @user_data: Function specific data
5587  * Returns: TRUE on success, FALSE on failure
5588  *
5589  * Getter for BSS age
5590  */
wpas_dbus_getter_bss_age(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5591 dbus_bool_t wpas_dbus_getter_bss_age(
5592 	const struct wpa_dbus_property_desc *property_desc,
5593 	DBusMessageIter *iter, DBusError *error, void *user_data)
5594 {
5595 	struct bss_handler_args *args = user_data;
5596 	struct wpa_bss *res;
5597 	struct os_reltime now, diff = { 0, 0 };
5598 	u32 age;
5599 
5600 	res = get_bss_helper(args, error, __func__);
5601 	if (!res)
5602 		return FALSE;
5603 
5604 	os_get_reltime(&now);
5605 	os_reltime_sub(&now, &res->last_update, &diff);
5606 	age = diff.sec > 0 ? diff.sec : 0;
5607 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
5608 						error);
5609 }
5610 
5611 
5612 /**
5613  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
5614  * @iter: Pointer to incoming dbus message iter
5615  * @error: Location to store error on failure
5616  * @user_data: Function specific data
5617  * Returns: TRUE on success, FALSE on failure
5618  *
5619  * Getter for "enabled" property of a configured network.
5620  */
wpas_dbus_getter_enabled(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5621 dbus_bool_t wpas_dbus_getter_enabled(
5622 	const struct wpa_dbus_property_desc *property_desc,
5623 	DBusMessageIter *iter, DBusError *error, void *user_data)
5624 {
5625 	struct network_handler_args *net = user_data;
5626 	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
5627 
5628 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
5629 						&enabled, error);
5630 }
5631 
5632 
5633 /**
5634  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
5635  * @iter: Pointer to incoming dbus message iter
5636  * @error: Location to store error on failure
5637  * @user_data: Function specific data
5638  * Returns: TRUE on success, FALSE on failure
5639  *
5640  * Setter for "Enabled" property of a configured network.
5641  */
wpas_dbus_setter_enabled(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5642 dbus_bool_t wpas_dbus_setter_enabled(
5643 	const struct wpa_dbus_property_desc *property_desc,
5644 	DBusMessageIter *iter, DBusError *error, void *user_data)
5645 {
5646 	struct network_handler_args *net = user_data;
5647 	struct wpa_supplicant *wpa_s;
5648 	struct wpa_ssid *ssid;
5649 	dbus_bool_t enable;
5650 
5651 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
5652 					      &enable))
5653 		return FALSE;
5654 
5655 	wpa_s = net->wpa_s;
5656 	ssid = net->ssid;
5657 
5658 	if (enable)
5659 		wpa_supplicant_enable_network(wpa_s, ssid);
5660 	else
5661 		wpa_supplicant_disable_network(wpa_s, ssid);
5662 
5663 	return TRUE;
5664 }
5665 
5666 
5667 /**
5668  * wpas_dbus_getter_network_properties - Get options for a configured network
5669  * @iter: Pointer to incoming dbus message iter
5670  * @error: Location to store error on failure
5671  * @user_data: Function specific data
5672  * Returns: TRUE on success, FALSE on failure
5673  *
5674  * Getter for "Properties" property of a configured network.
5675  */
wpas_dbus_getter_network_properties(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5676 dbus_bool_t wpas_dbus_getter_network_properties(
5677 	const struct wpa_dbus_property_desc *property_desc,
5678 	DBusMessageIter *iter, DBusError *error, void *user_data)
5679 {
5680 	struct network_handler_args *net = user_data;
5681 	DBusMessageIter	variant_iter, dict_iter;
5682 	char **iterator;
5683 	char **props = wpa_config_get_all(net->ssid, 1);
5684 	dbus_bool_t success = FALSE;
5685 
5686 	if (!props) {
5687 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5688 		return FALSE;
5689 	}
5690 
5691 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
5692 					      &variant_iter) ||
5693 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
5694 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5695 		goto out;
5696 	}
5697 
5698 	iterator = props;
5699 	while (*iterator) {
5700 		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
5701 						 *(iterator + 1))) {
5702 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
5703 					     "no memory");
5704 			goto out;
5705 		}
5706 		iterator += 2;
5707 	}
5708 
5709 
5710 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
5711 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
5712 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
5713 		goto out;
5714 	}
5715 
5716 	success = TRUE;
5717 
5718 out:
5719 	iterator = props;
5720 	while (*iterator) {
5721 		os_free(*iterator);
5722 		iterator++;
5723 	}
5724 	os_free(props);
5725 	return success;
5726 }
5727 
5728 
5729 /**
5730  * wpas_dbus_setter_network_properties - Set options for a configured network
5731  * @iter: Pointer to incoming dbus message iter
5732  * @error: Location to store error on failure
5733  * @user_data: Function specific data
5734  * Returns: TRUE on success, FALSE on failure
5735  *
5736  * Setter for "Properties" property of a configured network.
5737  */
wpas_dbus_setter_network_properties(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5738 dbus_bool_t wpas_dbus_setter_network_properties(
5739 	const struct wpa_dbus_property_desc *property_desc,
5740 	DBusMessageIter *iter, DBusError *error, void *user_data)
5741 {
5742 	struct network_handler_args *net = user_data;
5743 	struct wpa_ssid *ssid = net->ssid;
5744 	DBusMessageIter	variant_iter;
5745 
5746 	dbus_message_iter_recurse(iter, &variant_iter);
5747 	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
5748 }
5749 
5750 
5751 #ifdef CONFIG_AP
5752 
wpas_dbus_handler_subscribe_preq(DBusMessage * message,struct wpa_supplicant * wpa_s)5753 DBusMessage * wpas_dbus_handler_subscribe_preq(
5754 	DBusMessage *message, struct wpa_supplicant *wpa_s)
5755 {
5756 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5757 	char *name;
5758 
5759 	if (wpa_s->preq_notify_peer != NULL) {
5760 		if (os_strcmp(dbus_message_get_sender(message),
5761 			      wpa_s->preq_notify_peer) == 0)
5762 			return NULL;
5763 
5764 		return dbus_message_new_error(message,
5765 			WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
5766 			"Another application is already subscribed");
5767 	}
5768 
5769 	name = os_strdup(dbus_message_get_sender(message));
5770 	if (!name)
5771 		return wpas_dbus_error_no_memory(message);
5772 
5773 	wpa_s->preq_notify_peer = name;
5774 
5775 	/* Subscribe to clean up if application closes socket */
5776 	wpas_dbus_subscribe_noc(priv);
5777 
5778 	/*
5779 	 * Double-check it's still alive to make sure that we didn't
5780 	 * miss the NameOwnerChanged signal, e.g. while strdup'ing.
5781 	 */
5782 	if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
5783 		/*
5784 		 * Application no longer exists, clean up.
5785 		 * The return value is irrelevant now.
5786 		 *
5787 		 * Need to check if the NameOwnerChanged handling
5788 		 * already cleaned up because we have processed
5789 		 * DBus messages while checking if the name still
5790 		 * has an owner.
5791 		 */
5792 		if (!wpa_s->preq_notify_peer)
5793 			return NULL;
5794 		os_free(wpa_s->preq_notify_peer);
5795 		wpa_s->preq_notify_peer = NULL;
5796 		wpas_dbus_unsubscribe_noc(priv);
5797 	}
5798 
5799 	return NULL;
5800 }
5801 
5802 
wpas_dbus_handler_unsubscribe_preq(DBusMessage * message,struct wpa_supplicant * wpa_s)5803 DBusMessage * wpas_dbus_handler_unsubscribe_preq(
5804 	DBusMessage *message, struct wpa_supplicant *wpa_s)
5805 {
5806 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5807 
5808 	if (!wpa_s->preq_notify_peer)
5809 		return dbus_message_new_error(message,
5810 			WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
5811 			"Not subscribed");
5812 
5813 	if (os_strcmp(wpa_s->preq_notify_peer,
5814 		      dbus_message_get_sender(message)))
5815 		return dbus_message_new_error(message,
5816 			WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
5817 			"Can't unsubscribe others");
5818 
5819 	os_free(wpa_s->preq_notify_peer);
5820 	wpa_s->preq_notify_peer = NULL;
5821 	wpas_dbus_unsubscribe_noc(priv);
5822 	return NULL;
5823 }
5824 
5825 
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)5826 void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
5827 			   const u8 *addr, const u8 *dst, const u8 *bssid,
5828 			   const u8 *ie, size_t ie_len, u32 ssi_signal)
5829 {
5830 	DBusMessage *msg;
5831 	DBusMessageIter iter, dict_iter;
5832 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5833 
5834 	/* Do nothing if the control interface is not turned on */
5835 	if (priv == NULL || !wpa_s->dbus_new_path)
5836 		return;
5837 
5838 	if (wpa_s->preq_notify_peer == NULL)
5839 		return;
5840 
5841 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
5842 				      WPAS_DBUS_NEW_IFACE_INTERFACE,
5843 				      "ProbeRequest");
5844 	if (msg == NULL)
5845 		return;
5846 
5847 	dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
5848 
5849 	dbus_message_iter_init_append(msg, &iter);
5850 
5851 	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
5852 	    (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
5853 						      (const char *) addr,
5854 						      ETH_ALEN)) ||
5855 	    (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
5856 						     (const char *) dst,
5857 						     ETH_ALEN)) ||
5858 	    (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
5859 						       (const char *) bssid,
5860 						       ETH_ALEN)) ||
5861 	    (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
5862 							      (const char *) ie,
5863 							      ie_len)) ||
5864 	    (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
5865 						       ssi_signal)) ||
5866 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
5867 		goto fail;
5868 
5869 	dbus_connection_send(priv->con, msg, NULL);
5870 	goto out;
5871 fail:
5872 	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
5873 out:
5874 	dbus_message_unref(msg);
5875 }
5876 
5877 #endif /* CONFIG_AP */
5878 
5879 
wpas_dbus_handler_vendor_elem_add(DBusMessage * message,struct wpa_supplicant * wpa_s)5880 DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
5881 						struct wpa_supplicant *wpa_s)
5882 {
5883 	u8 *ielems;
5884 	int len;
5885 	struct ieee802_11_elems elems;
5886 	dbus_int32_t frame_id;
5887 	DBusMessageIter	iter, array;
5888 
5889 	dbus_message_iter_init(message, &iter);
5890 	dbus_message_iter_get_basic(&iter, &frame_id);
5891 	if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5892 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5893 					      "Invalid ID");
5894 	}
5895 
5896 	dbus_message_iter_next(&iter);
5897 	dbus_message_iter_recurse(&iter, &array);
5898 	dbus_message_iter_get_fixed_array(&array, &ielems, &len);
5899 	if (!ielems || len == 0) {
5900 		return dbus_message_new_error(
5901 			message, DBUS_ERROR_INVALID_ARGS, "Invalid value");
5902 	}
5903 
5904 	if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
5905 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5906 					      "Parse error");
5907 	}
5908 
5909 	wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5910 	if (!wpa_s->vendor_elem[frame_id]) {
5911 		wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len);
5912 		wpas_vendor_elem_update(wpa_s);
5913 		return NULL;
5914 	}
5915 
5916 	if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) {
5917 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5918 					      "Resize error");
5919 	}
5920 
5921 	wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len);
5922 	wpas_vendor_elem_update(wpa_s);
5923 	return NULL;
5924 }
5925 
5926 
wpas_dbus_handler_vendor_elem_get(DBusMessage * message,struct wpa_supplicant * wpa_s)5927 DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
5928 						struct wpa_supplicant *wpa_s)
5929 {
5930 	DBusMessage *reply;
5931 	DBusMessageIter	iter, array_iter;
5932 	dbus_int32_t frame_id;
5933 	const u8 *elem;
5934 	size_t elem_len;
5935 
5936 	dbus_message_iter_init(message, &iter);
5937 	dbus_message_iter_get_basic(&iter, &frame_id);
5938 
5939 	if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5940 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5941 					      "Invalid ID");
5942 	}
5943 
5944 	wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5945 	if (!wpa_s->vendor_elem[frame_id]) {
5946 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5947 					      "ID value does not exist");
5948 	}
5949 
5950 	reply = dbus_message_new_method_return(message);
5951 	if (!reply)
5952 		return wpas_dbus_error_no_memory(message);
5953 
5954 	dbus_message_iter_init_append(reply, &iter);
5955 
5956 	elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]);
5957 	elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
5958 
5959 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
5960 					      DBUS_TYPE_BYTE_AS_STRING,
5961 					      &array_iter) ||
5962 	    !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
5963 						  &elem, elem_len) ||
5964 	    !dbus_message_iter_close_container(&iter, &array_iter)) {
5965 		dbus_message_unref(reply);
5966 		reply = wpas_dbus_error_no_memory(message);
5967 	}
5968 
5969 	return reply;
5970 }
5971 
5972 
wpas_dbus_handler_vendor_elem_remove(DBusMessage * message,struct wpa_supplicant * wpa_s)5973 DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message,
5974 						   struct wpa_supplicant *wpa_s)
5975 {
5976 	u8 *ielems;
5977 	int len;
5978 	struct ieee802_11_elems elems;
5979 	DBusMessageIter	iter, array;
5980 	dbus_int32_t frame_id;
5981 
5982 	dbus_message_iter_init(message, &iter);
5983 	dbus_message_iter_get_basic(&iter, &frame_id);
5984 	if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5985 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5986 					      "Invalid ID");
5987 	}
5988 
5989 	dbus_message_iter_next(&iter);
5990 	dbus_message_iter_recurse(&iter, &array);
5991 	dbus_message_iter_get_fixed_array(&array, &ielems, &len);
5992 	if (!ielems || len == 0) {
5993 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5994 					      "Invalid value");
5995 	}
5996 
5997 	wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5998 
5999 	if (len == 1 && *ielems == '*') {
6000 		wpabuf_free(wpa_s->vendor_elem[frame_id]);
6001 		wpa_s->vendor_elem[frame_id] = NULL;
6002 		wpas_vendor_elem_update(wpa_s);
6003 		return NULL;
6004 	}
6005 
6006 	if (!wpa_s->vendor_elem[frame_id]) {
6007 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
6008 					      "ID value does not exist");
6009 	}
6010 
6011 	if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
6012 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
6013 					      "Parse error");
6014 	}
6015 
6016 	if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0)
6017 		return NULL;
6018 
6019 	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
6020 				      "Not found");
6021 }
6022 
6023 
6024 #ifdef CONFIG_MESH
6025 
6026 /**
6027  * wpas_dbus_getter_mesh_peers - Get connected mesh peers
6028  * @iter: Pointer to incoming dbus message iter
6029  * @error: Location to store error on failure
6030  * @user_data: Function specific data
6031  * Returns: TRUE on success, FALSE on failure
6032  *
6033  * Getter for "MeshPeers" property.
6034  */
wpas_dbus_getter_mesh_peers(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)6035 dbus_bool_t wpas_dbus_getter_mesh_peers(
6036 	const struct wpa_dbus_property_desc *property_desc,
6037 	DBusMessageIter *iter, DBusError *error, void *user_data)
6038 {
6039 	struct wpa_supplicant *wpa_s = user_data;
6040 	struct hostapd_data *hapd;
6041 	struct sta_info *sta;
6042 	DBusMessageIter variant_iter, array_iter;
6043 	int i;
6044 	DBusMessageIter inner_array_iter;
6045 
6046 	if (!wpa_s->ifmsh)
6047 		return FALSE;
6048 	hapd = wpa_s->ifmsh->bss[0];
6049 
6050 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
6051 					      DBUS_TYPE_ARRAY_AS_STRING
6052 					      DBUS_TYPE_ARRAY_AS_STRING
6053 					      DBUS_TYPE_BYTE_AS_STRING,
6054 					      &variant_iter) ||
6055 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
6056 					      DBUS_TYPE_ARRAY_AS_STRING
6057 					      DBUS_TYPE_BYTE_AS_STRING,
6058 					      &array_iter))
6059 		return FALSE;
6060 
6061 	for (sta = hapd->sta_list; sta; sta = sta->next) {
6062 		if (!dbus_message_iter_open_container(
6063 			    &array_iter, DBUS_TYPE_ARRAY,
6064 			    DBUS_TYPE_BYTE_AS_STRING,
6065 			    &inner_array_iter))
6066 			return FALSE;
6067 
6068 		for (i = 0; i < ETH_ALEN; i++) {
6069 			if (!dbus_message_iter_append_basic(&inner_array_iter,
6070 							    DBUS_TYPE_BYTE,
6071 							    &(sta->addr[i])))
6072 				return FALSE;
6073 		}
6074 
6075 		if (!dbus_message_iter_close_container(
6076 			    &array_iter, &inner_array_iter))
6077 			return FALSE;
6078 	}
6079 
6080 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
6081 	    !dbus_message_iter_close_container(iter, &variant_iter))
6082 		return FALSE;
6083 
6084 	return TRUE;
6085 }
6086 
6087 
6088 /**
6089  * wpas_dbus_getter_mesh_group - Get mesh group
6090  * @iter: Pointer to incoming dbus message iter
6091  * @error: Location to store error on failure
6092  * @user_data: Function specific data
6093  * Returns: TRUE on success, FALSE on failure
6094  *
6095  * Getter for "MeshGroup" property.
6096  */
wpas_dbus_getter_mesh_group(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)6097 dbus_bool_t wpas_dbus_getter_mesh_group(
6098 	const struct wpa_dbus_property_desc *property_desc,
6099 	DBusMessageIter *iter, DBusError *error, void *user_data)
6100 {
6101 	struct wpa_supplicant *wpa_s = user_data;
6102 	struct wpa_ssid *ssid = wpa_s->current_ssid;
6103 
6104 	if (!wpa_s->ifmsh || !ssid)
6105 		return FALSE;
6106 
6107 	if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
6108 						    (char *) ssid->ssid,
6109 						    ssid->ssid_len, error)) {
6110 		dbus_set_error(error, DBUS_ERROR_FAILED,
6111 			       "%s: error constructing reply", __func__);
6112 		return FALSE;
6113 	}
6114 
6115 	return TRUE;
6116 }
6117 
6118 #endif /* CONFIG_MESH */
6119 
6120 
6121 /**
6122  * wpas_dbus_getter_signal_change - Get signal change
6123  * @iter: Pointer to incoming dbus message iter
6124  * @error: Location to store error on failure
6125  * @user_data: Function specific data
6126  * Returns: TRUE on success, FALSE on failure
6127  *
6128  * Getter for "SignalChange" property.
6129  */
wpas_dbus_getter_signal_change(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)6130 dbus_bool_t wpas_dbus_getter_signal_change(
6131 	const struct wpa_dbus_property_desc *property_desc,
6132 	DBusMessageIter *iter, DBusError *error, void *user_data)
6133 {
6134 	struct wpa_supplicant *wpa_s = user_data;
6135 	struct wpa_signal_info si = wpa_s->last_signal_info;
6136 
6137 	if (wpas_dbus_new_from_signal_information(iter, &si) != 0) {
6138 		dbus_set_error(error, DBUS_ERROR_FAILED,
6139 			       "%s: error constructing reply", __func__);
6140 		return FALSE;
6141 	}
6142 	return TRUE;
6143 }
6144