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