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