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