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 "../config.h"
19 #include "../wpa_supplicant_i.h"
20 #include "../driver_i.h"
21 #include "../notify.h"
22 #include "../bss.h"
23 #include "../scan.h"
24 #include "../autoscan.h"
25 #include "dbus_new_helpers.h"
26 #include "dbus_new.h"
27 #include "dbus_new_handlers.h"
28 #include "dbus_dict_helpers.h"
29 #include "dbus_common_i.h"
30 #include "drivers/driver.h"
31 
32 static const char * const debug_strings[] = {
33 	"excessive", "msgdump", "debug", "info", "warning", "error", NULL
34 };
35 
36 
37 /**
38  * wpas_dbus_error_unknown_error - Return a new UnknownError error message
39  * @message: Pointer to incoming dbus message this error refers to
40  * @arg: Optional string appended to error message
41  * Returns: a dbus error message
42  *
43  * Convenience function to create and return an UnknownError
44  */
wpas_dbus_error_unknown_error(DBusMessage * message,const char * arg)45 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
46 					    const char *arg)
47 {
48 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
49 				      arg);
50 }
51 
52 
53 /**
54  * wpas_dbus_error_iface_unknown - Return a new invalid interface error message
55  * @message: Pointer to incoming dbus message this error refers to
56  * Returns: A dbus error message
57  *
58  * Convenience function to create and return an invalid interface error
59  */
wpas_dbus_error_iface_unknown(DBusMessage * message)60 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
61 {
62 	return dbus_message_new_error(
63 		message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
64 		"wpa_supplicant knows nothing about this interface.");
65 }
66 
67 
68 /**
69  * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
70  * @message: Pointer to incoming dbus message this error refers to
71  * Returns: a dbus error message
72  *
73  * Convenience function to create and return an invalid network error
74  */
wpas_dbus_error_network_unknown(DBusMessage * message)75 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
76 {
77 	return dbus_message_new_error(
78 		message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
79 		"There is no such a network in this interface.");
80 }
81 
82 
83 /**
84  * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
85  * @message: Pointer to incoming dbus message this error refers to
86  * Returns: a dbus error message
87  *
88  * Convenience function to create and return an invalid options error
89  */
wpas_dbus_error_invalid_args(DBusMessage * message,const char * arg)90 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
91 					  const char *arg)
92 {
93 	DBusMessage *reply;
94 
95 	reply = dbus_message_new_error(
96 		message, WPAS_DBUS_ERROR_INVALID_ARGS,
97 		"Did not receive correct message arguments.");
98 	if (arg != NULL)
99 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
100 					 DBUS_TYPE_INVALID);
101 
102 	return reply;
103 }
104 
105 
106 /**
107  * wpas_dbus_error_scan_error - Return a new ScanError error message
108  * @message: Pointer to incoming dbus message this error refers to
109  * @error: Optional string to be used as the error message
110  * Returns: a dbus error message
111  *
112  * Convenience function to create and return a scan error
113  */
wpas_dbus_error_scan_error(DBusMessage * message,const char * error)114 static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
115 						const char *error)
116 {
117 	return dbus_message_new_error(message,
118 				      WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
119 				      error);
120 }
121 
122 
wpas_dbus_error_no_memory(DBusMessage * message)123 DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
124 {
125 	wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
126 	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
127 }
128 
129 
130 static const char * const dont_quote[] = {
131 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
132 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
133 	"bssid", "scan_freq", "freq_list", NULL
134 };
135 
should_quote_opt(const char * key)136 static dbus_bool_t should_quote_opt(const char *key)
137 {
138 	int i = 0;
139 
140 	while (dont_quote[i] != NULL) {
141 		if (os_strcmp(key, dont_quote[i]) == 0)
142 			return FALSE;
143 		i++;
144 	}
145 	return TRUE;
146 }
147 
148 /**
149  * get_iface_by_dbus_path - Get a new network interface
150  * @global: Pointer to global data from wpa_supplicant_init()
151  * @path: Pointer to a dbus object path representing an interface
152  * Returns: Pointer to the interface or %NULL if not found
153  */
get_iface_by_dbus_path(struct wpa_global * global,const char * path)154 static struct wpa_supplicant * get_iface_by_dbus_path(
155 	struct wpa_global *global, const char *path)
156 {
157 	struct wpa_supplicant *wpa_s;
158 
159 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
160 		if (wpa_s->dbus_new_path &&
161 		    os_strcmp(wpa_s->dbus_new_path, path) == 0)
162 			return wpa_s;
163 	}
164 	return NULL;
165 }
166 
167 
168 /**
169  * set_network_properties - Set properties of a configured network
170  * @wpa_s: wpa_supplicant structure for a network interface
171  * @ssid: wpa_ssid structure for a configured network
172  * @iter: DBus message iterator containing dictionary of network
173  * properties to set.
174  * @error: On failure, an error describing the failure
175  * Returns: TRUE if the request succeeds, FALSE if it failed
176  *
177  * Sets network configuration with parameters given id DBus dictionary
178  */
set_network_properties(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,DBusMessageIter * iter,DBusError * error)179 dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
180 				   struct wpa_ssid *ssid,
181 				   DBusMessageIter *iter,
182 				   DBusError *error)
183 {
184 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
185 	DBusMessageIter	iter_dict;
186 	char *value = NULL;
187 
188 	if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
189 		return FALSE;
190 
191 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
192 		size_t size = 50;
193 		int ret;
194 
195 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
196 			goto error;
197 
198 		value = NULL;
199 		if (entry.type == DBUS_TYPE_ARRAY &&
200 		    entry.array_type == DBUS_TYPE_BYTE) {
201 			if (entry.array_len <= 0)
202 				goto error;
203 
204 			size = entry.array_len * 2 + 1;
205 			value = os_zalloc(size);
206 			if (value == NULL)
207 				goto error;
208 
209 			ret = wpa_snprintf_hex(value, size,
210 					       (u8 *) entry.bytearray_value,
211 					       entry.array_len);
212 			if (ret <= 0)
213 				goto error;
214 		} else if (entry.type == DBUS_TYPE_STRING) {
215 			if (should_quote_opt(entry.key)) {
216 				size = os_strlen(entry.str_value);
217 				if (size == 0)
218 					goto error;
219 
220 				size += 3;
221 				value = os_zalloc(size);
222 				if (value == NULL)
223 					goto error;
224 
225 				ret = os_snprintf(value, size, "\"%s\"",
226 						  entry.str_value);
227 				if (os_snprintf_error(size, ret))
228 					goto error;
229 			} else {
230 				value = os_strdup(entry.str_value);
231 				if (value == NULL)
232 					goto error;
233 			}
234 		} else if (entry.type == DBUS_TYPE_UINT32) {
235 			value = os_zalloc(size);
236 			if (value == NULL)
237 				goto error;
238 
239 			ret = os_snprintf(value, size, "%u",
240 					  entry.uint32_value);
241 			if (os_snprintf_error(size, ret))
242 				goto error;
243 		} else if (entry.type == DBUS_TYPE_INT32) {
244 			value = os_zalloc(size);
245 			if (value == NULL)
246 				goto error;
247 
248 			ret = os_snprintf(value, size, "%d",
249 					  entry.int32_value);
250 			if (os_snprintf_error(size, ret))
251 				goto error;
252 		} else
253 			goto error;
254 
255 		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
256 			goto error;
257 
258 		if (os_strcmp(entry.key, "bssid") != 0 &&
259 		    os_strcmp(entry.key, "priority") != 0)
260 			wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
261 
262 		if (wpa_s->current_ssid == ssid ||
263 		    wpa_s->current_ssid == NULL) {
264 			/*
265 			 * Invalidate the EAP session cache if anything in the
266 			 * current or previously used configuration changes.
267 			 */
268 			eapol_sm_invalidate_cached_session(wpa_s->eapol);
269 		}
270 
271 		if ((os_strcmp(entry.key, "psk") == 0 &&
272 		     value[0] == '"' && ssid->ssid_len) ||
273 		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
274 			wpa_config_update_psk(ssid);
275 		else if (os_strcmp(entry.key, "priority") == 0)
276 			wpa_config_update_prio_list(wpa_s->conf);
277 
278 		os_free(value);
279 		value = NULL;
280 		wpa_dbus_dict_entry_clear(&entry);
281 	}
282 
283 	return TRUE;
284 
285 error:
286 	os_free(value);
287 	wpa_dbus_dict_entry_clear(&entry);
288 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
289 			     "invalid message format");
290 	return FALSE;
291 }
292 
293 
294 /**
295  * wpas_dbus_simple_property_getter - Get basic type property
296  * @iter: Message iter to use when appending arguments
297  * @type: DBus type of property (must be basic type)
298  * @val: pointer to place holding property value
299  * @error: On failure an error describing the failure
300  * Returns: TRUE if the request was successful, FALSE if it failed
301  *
302  * Generic getter for basic type properties. Type is required to be basic.
303  */
wpas_dbus_simple_property_getter(DBusMessageIter * iter,const int type,const void * val,DBusError * error)304 dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
305 					     const int type,
306 					     const void *val,
307 					     DBusError *error)
308 {
309 	DBusMessageIter variant_iter;
310 
311 	if (!dbus_type_is_basic(type)) {
312 		dbus_set_error(error, DBUS_ERROR_FAILED,
313 			       "%s: given type is not basic", __func__);
314 		return FALSE;
315 	}
316 
317 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
318 					      wpa_dbus_type_as_string(type),
319 					      &variant_iter) ||
320 	    !dbus_message_iter_append_basic(&variant_iter, type, val) ||
321 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
322 		dbus_set_error(error, DBUS_ERROR_FAILED,
323 			       "%s: error constructing reply", __func__);
324 		return FALSE;
325 	}
326 
327 	return TRUE;
328 }
329 
330 
331 /**
332  * wpas_dbus_simple_property_setter - Set basic type property
333  * @message: Pointer to incoming dbus message
334  * @type: DBus type of property (must be basic type)
335  * @val: pointer to place where value being set will be stored
336  * Returns: TRUE if the request was successful, FALSE if it failed
337  *
338  * Generic setter for basic type properties. Type is required to be basic.
339  */
wpas_dbus_simple_property_setter(DBusMessageIter * iter,DBusError * error,const int type,void * val)340 dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
341 					     DBusError *error,
342 					     const int type, void *val)
343 {
344 	DBusMessageIter variant_iter;
345 
346 	if (!dbus_type_is_basic(type)) {
347 		dbus_set_error(error, DBUS_ERROR_FAILED,
348 			       "%s: given type is not basic", __func__);
349 		return FALSE;
350 	}
351 
352 	/* Look at the new value */
353 	dbus_message_iter_recurse(iter, &variant_iter);
354 	if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
355 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
356 				     "wrong property type");
357 		return FALSE;
358 	}
359 	dbus_message_iter_get_basic(&variant_iter, val);
360 
361 	return TRUE;
362 }
363 
364 
365 /**
366  * wpas_dbus_simple_array_property_getter - Get array type property
367  * @iter: Pointer to incoming dbus message iterator
368  * @type: DBus type of property array elements (must be basic type)
369  * @array: pointer to array of elements to put into response message
370  * @array_len: length of above array
371  * @error: a pointer to an error to fill on failure
372  * Returns: TRUE if the request succeeded, FALSE if it failed
373  *
374  * Generic getter for array type properties. Array elements type is
375  * required to be basic.
376  */
wpas_dbus_simple_array_property_getter(DBusMessageIter * iter,const int type,const void * array,size_t array_len,DBusError * error)377 dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
378 						   const int type,
379 						   const void *array,
380 						   size_t array_len,
381 						   DBusError *error)
382 {
383 	DBusMessageIter variant_iter, array_iter;
384 	char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
385 	const char *sub_type_str;
386 	size_t element_size, i;
387 
388 	if (!dbus_type_is_basic(type)) {
389 		dbus_set_error(error, DBUS_ERROR_FAILED,
390 			       "%s: given type is not basic", __func__);
391 		return FALSE;
392 	}
393 
394 	sub_type_str = wpa_dbus_type_as_string(type);
395 	type_str[1] = sub_type_str[0];
396 
397 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
398 					      type_str, &variant_iter) ||
399 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
400 					      sub_type_str, &array_iter)) {
401 		dbus_set_error(error, DBUS_ERROR_FAILED,
402 			       "%s: failed to construct message", __func__);
403 		return FALSE;
404 	}
405 
406 	switch (type) {
407 	case DBUS_TYPE_BYTE:
408 	case DBUS_TYPE_BOOLEAN:
409 		element_size = 1;
410 		break;
411 	case DBUS_TYPE_INT16:
412 	case DBUS_TYPE_UINT16:
413 		element_size = sizeof(uint16_t);
414 		break;
415 	case DBUS_TYPE_INT32:
416 	case DBUS_TYPE_UINT32:
417 		element_size = sizeof(uint32_t);
418 		break;
419 	case DBUS_TYPE_INT64:
420 	case DBUS_TYPE_UINT64:
421 		element_size = sizeof(uint64_t);
422 		break;
423 	case DBUS_TYPE_DOUBLE:
424 		element_size = sizeof(double);
425 		break;
426 	case DBUS_TYPE_STRING:
427 	case DBUS_TYPE_OBJECT_PATH:
428 		element_size = sizeof(char *);
429 		break;
430 	default:
431 		dbus_set_error(error, DBUS_ERROR_FAILED,
432 			       "%s: unknown element type %d", __func__, type);
433 		return FALSE;
434 	}
435 
436 	for (i = 0; i < array_len; i++) {
437 		if (!dbus_message_iter_append_basic(&array_iter, type,
438 						    array + i * element_size)) {
439 			dbus_set_error(error, DBUS_ERROR_FAILED,
440 				       "%s: failed to construct message 2.5",
441 				       __func__);
442 			return FALSE;
443 		}
444 	}
445 
446 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
447 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
448 		dbus_set_error(error, DBUS_ERROR_FAILED,
449 			       "%s: failed to construct message 3", __func__);
450 		return FALSE;
451 	}
452 
453 	return TRUE;
454 }
455 
456 
457 /**
458  * wpas_dbus_simple_array_array_property_getter - Get array array type property
459  * @iter: Pointer to incoming dbus message iterator
460  * @type: DBus type of property array elements (must be basic type)
461  * @array: pointer to array of elements to put into response message
462  * @array_len: length of above array
463  * @error: a pointer to an error to fill on failure
464  * Returns: TRUE if the request succeeded, FALSE if it failed
465  *
466  * Generic getter for array type properties. Array elements type is
467  * required to be basic.
468  */
wpas_dbus_simple_array_array_property_getter(DBusMessageIter * iter,const int type,struct wpabuf ** array,size_t array_len,DBusError * error)469 dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
470 							 const int type,
471 							 struct wpabuf **array,
472 							 size_t array_len,
473 							 DBusError *error)
474 {
475 	DBusMessageIter variant_iter, array_iter;
476 	char type_str[] = "aa?";
477 	char inner_type_str[] = "a?";
478 	const char *sub_type_str;
479 	size_t i;
480 
481 	if (!dbus_type_is_basic(type)) {
482 		dbus_set_error(error, DBUS_ERROR_FAILED,
483 			       "%s: given type is not basic", __func__);
484 		return FALSE;
485 	}
486 
487 	sub_type_str = wpa_dbus_type_as_string(type);
488 	type_str[2] = sub_type_str[0];
489 	inner_type_str[1] = sub_type_str[0];
490 
491 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
492 					      type_str, &variant_iter) ||
493 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
494 					      inner_type_str, &array_iter)) {
495 		dbus_set_error(error, DBUS_ERROR_FAILED,
496 			       "%s: failed to construct message", __func__);
497 		return FALSE;
498 	}
499 
500 	for (i = 0; i < array_len && array[i]; i++) {
501 		wpa_dbus_dict_bin_array_add_element(&array_iter,
502 						    wpabuf_head(array[i]),
503 						    wpabuf_len(array[i]));
504 
505 	}
506 
507 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
508 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
509 		dbus_set_error(error, DBUS_ERROR_FAILED,
510 			       "%s: failed to close message", __func__);
511 		return FALSE;
512 	}
513 
514 	return TRUE;
515 }
516 
517 
518 /**
519  * wpas_dbus_handler_create_interface - Request registration of a network iface
520  * @message: Pointer to incoming dbus message
521  * @global: %wpa_supplicant global data structure
522  * Returns: The object path of the new interface object,
523  *          or a dbus error message with more information
524  *
525  * Handler function for "CreateInterface" method call. Handles requests
526  * by dbus clients to register a network interface that wpa_supplicant
527  * will manage.
528  */
wpas_dbus_handler_create_interface(DBusMessage * message,struct wpa_global * global)529 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
530 						 struct wpa_global *global)
531 {
532 	DBusMessageIter iter_dict;
533 	DBusMessage *reply = NULL;
534 	DBusMessageIter iter;
535 	struct wpa_dbus_dict_entry entry;
536 	char *driver = NULL;
537 	char *ifname = NULL;
538 	char *confname = NULL;
539 	char *bridge_ifname = NULL;
540 
541 	dbus_message_iter_init(message, &iter);
542 
543 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
544 		goto error;
545 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
546 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
547 			goto error;
548 		if (os_strcmp(entry.key, "Driver") == 0 &&
549 		    entry.type == DBUS_TYPE_STRING) {
550 			os_free(driver);
551 			driver = os_strdup(entry.str_value);
552 			wpa_dbus_dict_entry_clear(&entry);
553 			if (driver == NULL)
554 				goto oom;
555 		} else if (os_strcmp(entry.key, "Ifname") == 0 &&
556 			   entry.type == DBUS_TYPE_STRING) {
557 			os_free(ifname);
558 			ifname = os_strdup(entry.str_value);
559 			wpa_dbus_dict_entry_clear(&entry);
560 			if (ifname == NULL)
561 				goto oom;
562 		} else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
563 			   entry.type == DBUS_TYPE_STRING) {
564 			os_free(confname);
565 			confname = os_strdup(entry.str_value);
566 			wpa_dbus_dict_entry_clear(&entry);
567 			if (confname == NULL)
568 				goto oom;
569 		} else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
570 			   entry.type == DBUS_TYPE_STRING) {
571 			os_free(bridge_ifname);
572 			bridge_ifname = os_strdup(entry.str_value);
573 			wpa_dbus_dict_entry_clear(&entry);
574 			if (bridge_ifname == NULL)
575 				goto oom;
576 		} else {
577 			wpa_dbus_dict_entry_clear(&entry);
578 			goto error;
579 		}
580 	}
581 
582 	if (ifname == NULL)
583 		goto error; /* Required Ifname argument missing */
584 
585 	/*
586 	 * Try to get the wpa_supplicant record for this iface, return
587 	 * an error if we already control it.
588 	 */
589 	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
590 		reply = dbus_message_new_error(
591 			message, WPAS_DBUS_ERROR_IFACE_EXISTS,
592 			"wpa_supplicant already controls this interface.");
593 	} else {
594 		struct wpa_supplicant *wpa_s;
595 		struct wpa_interface iface;
596 
597 		os_memset(&iface, 0, sizeof(iface));
598 		iface.driver = driver;
599 		iface.ifname = ifname;
600 		iface.confname = confname;
601 		iface.bridge_ifname = bridge_ifname;
602 		/* Otherwise, have wpa_supplicant attach to it. */
603 		wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
604 		if (wpa_s && wpa_s->dbus_new_path) {
605 			const char *path = wpa_s->dbus_new_path;
606 
607 			reply = dbus_message_new_method_return(message);
608 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
609 						 &path, DBUS_TYPE_INVALID);
610 		} else {
611 			reply = wpas_dbus_error_unknown_error(
612 				message,
613 				"wpa_supplicant couldn't grab this interface.");
614 		}
615 	}
616 
617 out:
618 	os_free(driver);
619 	os_free(ifname);
620 	os_free(confname);
621 	os_free(bridge_ifname);
622 	return reply;
623 
624 error:
625 	reply = wpas_dbus_error_invalid_args(message, NULL);
626 	goto out;
627 oom:
628 	reply = wpas_dbus_error_no_memory(message);
629 	goto out;
630 }
631 
632 
633 /**
634  * wpas_dbus_handler_remove_interface - Request deregistration of an interface
635  * @message: Pointer to incoming dbus message
636  * @global: wpa_supplicant global data structure
637  * Returns: a dbus message containing a UINT32 indicating success (1) or
638  *          failure (0), or returns a dbus error message with more information
639  *
640  * Handler function for "removeInterface" method call.  Handles requests
641  * by dbus clients to deregister a network interface that wpa_supplicant
642  * currently manages.
643  */
wpas_dbus_handler_remove_interface(DBusMessage * message,struct wpa_global * global)644 DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
645 						 struct wpa_global *global)
646 {
647 	struct wpa_supplicant *wpa_s;
648 	char *path;
649 	DBusMessage *reply = NULL;
650 
651 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
652 			      DBUS_TYPE_INVALID);
653 
654 	wpa_s = get_iface_by_dbus_path(global, path);
655 	if (wpa_s == NULL)
656 		reply = wpas_dbus_error_iface_unknown(message);
657 	else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
658 		reply = wpas_dbus_error_unknown_error(
659 			message,
660 			"wpa_supplicant couldn't remove this interface.");
661 	}
662 
663 	return reply;
664 }
665 
666 
667 /**
668  * wpas_dbus_handler_get_interface - Get the object path for an interface name
669  * @message: Pointer to incoming dbus message
670  * @global: %wpa_supplicant global data structure
671  * Returns: The object path of the interface object,
672  *          or a dbus error message with more information
673  *
674  * Handler function for "getInterface" method call.
675  */
wpas_dbus_handler_get_interface(DBusMessage * message,struct wpa_global * global)676 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
677 					      struct wpa_global *global)
678 {
679 	DBusMessage *reply = NULL;
680 	const char *ifname;
681 	const char *path;
682 	struct wpa_supplicant *wpa_s;
683 
684 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
685 			      DBUS_TYPE_INVALID);
686 
687 	wpa_s = wpa_supplicant_get_iface(global, ifname);
688 	if (wpa_s == NULL || wpa_s->dbus_new_path == NULL)
689 		return wpas_dbus_error_iface_unknown(message);
690 
691 	path = wpa_s->dbus_new_path;
692 	reply = dbus_message_new_method_return(message);
693 	if (reply == NULL)
694 		return wpas_dbus_error_no_memory(message);
695 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
696 				      DBUS_TYPE_INVALID)) {
697 		dbus_message_unref(reply);
698 		return wpas_dbus_error_no_memory(message);
699 	}
700 
701 	return reply;
702 }
703 
704 
705 /**
706  * wpas_dbus_getter_debug_level - Get debug level
707  * @iter: Pointer to incoming dbus message iter
708  * @error: Location to store error on failure
709  * @user_data: Function specific data
710  * Returns: TRUE on success, FALSE on failure
711  *
712  * Getter for "DebugLevel" property.
713  */
wpas_dbus_getter_debug_level(DBusMessageIter * iter,DBusError * error,void * user_data)714 dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
715 					 DBusError *error,
716 					 void *user_data)
717 {
718 	const char *str;
719 	int idx = wpa_debug_level;
720 
721 	if (idx < 0)
722 		idx = 0;
723 	if (idx > 5)
724 		idx = 5;
725 	str = debug_strings[idx];
726 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
727 						&str, error);
728 }
729 
730 
731 /**
732  * wpas_dbus_getter_debug_timestamp - Get debug timestamp
733  * @iter: Pointer to incoming dbus message iter
734  * @error: Location to store error on failure
735  * @user_data: Function specific data
736  * Returns: TRUE on success, FALSE on failure
737  *
738  * Getter for "DebugTimestamp" property.
739  */
wpas_dbus_getter_debug_timestamp(DBusMessageIter * iter,DBusError * error,void * user_data)740 dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
741 					     DBusError *error,
742 					     void *user_data)
743 {
744 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
745 						&wpa_debug_timestamp, error);
746 
747 }
748 
749 
750 /**
751  * wpas_dbus_getter_debug_show_keys - Get debug show keys
752  * @iter: Pointer to incoming dbus message iter
753  * @error: Location to store error on failure
754  * @user_data: Function specific data
755  * Returns: TRUE on success, FALSE on failure
756  *
757  * Getter for "DebugShowKeys" property.
758  */
wpas_dbus_getter_debug_show_keys(DBusMessageIter * iter,DBusError * error,void * user_data)759 dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
760 					     DBusError *error,
761 					     void *user_data)
762 {
763 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
764 						&wpa_debug_show_keys, error);
765 
766 }
767 
768 /**
769  * wpas_dbus_setter_debug_level - Set debug level
770  * @iter: Pointer to incoming dbus message iter
771  * @error: Location to store error on failure
772  * @user_data: Function specific data
773  * Returns: TRUE on success, FALSE on failure
774  *
775  * Setter for "DebugLevel" property.
776  */
wpas_dbus_setter_debug_level(DBusMessageIter * iter,DBusError * error,void * user_data)777 dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
778 					 DBusError *error, void *user_data)
779 {
780 	struct wpa_global *global = user_data;
781 	const char *str = NULL;
782 	int i, val = -1;
783 
784 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
785 					      &str))
786 		return FALSE;
787 
788 	for (i = 0; debug_strings[i]; i++)
789 		if (os_strcmp(debug_strings[i], str) == 0) {
790 			val = i;
791 			break;
792 		}
793 
794 	if (val < 0 ||
795 	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
796 					    wpa_debug_show_keys)) {
797 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
798 				     "wrong debug level value");
799 		return FALSE;
800 	}
801 
802 	return TRUE;
803 }
804 
805 
806 /**
807  * wpas_dbus_setter_debug_timestamp - Set debug timestamp
808  * @iter: Pointer to incoming dbus message iter
809  * @error: Location to store error on failure
810  * @user_data: Function specific data
811  * Returns: TRUE on success, FALSE on failure
812  *
813  * Setter for "DebugTimestamp" property.
814  */
wpas_dbus_setter_debug_timestamp(DBusMessageIter * iter,DBusError * error,void * user_data)815 dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
816 					     DBusError *error,
817 					     void *user_data)
818 {
819 	struct wpa_global *global = user_data;
820 	dbus_bool_t val;
821 
822 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
823 					      &val))
824 		return FALSE;
825 
826 	wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
827 					wpa_debug_show_keys);
828 	return TRUE;
829 }
830 
831 
832 /**
833  * wpas_dbus_setter_debug_show_keys - Set debug show keys
834  * @iter: Pointer to incoming dbus message iter
835  * @error: Location to store error on failure
836  * @user_data: Function specific data
837  * Returns: TRUE on success, FALSE on failure
838  *
839  * Setter for "DebugShowKeys" property.
840  */
wpas_dbus_setter_debug_show_keys(DBusMessageIter * iter,DBusError * error,void * user_data)841 dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
842 					     DBusError *error,
843 					     void *user_data)
844 {
845 	struct wpa_global *global = user_data;
846 	dbus_bool_t val;
847 
848 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
849 					      &val))
850 		return FALSE;
851 
852 	wpa_supplicant_set_debug_params(global, wpa_debug_level,
853 					wpa_debug_timestamp,
854 					val ? 1 : 0);
855 	return TRUE;
856 }
857 
858 
859 /**
860  * wpas_dbus_getter_interfaces - Request registered interfaces list
861  * @iter: Pointer to incoming dbus message iter
862  * @error: Location to store error on failure
863  * @user_data: Function specific data
864  * Returns: TRUE on success, FALSE on failure
865  *
866  * Getter for "Interfaces" property. Handles requests
867  * by dbus clients to return list of registered interfaces objects
868  * paths
869  */
wpas_dbus_getter_interfaces(DBusMessageIter * iter,DBusError * error,void * user_data)870 dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
871 					DBusError *error,
872 					void *user_data)
873 {
874 	struct wpa_global *global = user_data;
875 	struct wpa_supplicant *wpa_s;
876 	const char **paths;
877 	unsigned int i = 0, num = 0;
878 	dbus_bool_t success;
879 
880 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
881 		if (wpa_s->dbus_new_path)
882 			num++;
883 	}
884 
885 	paths = os_calloc(num, sizeof(char *));
886 	if (!paths) {
887 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
888 		return FALSE;
889 	}
890 
891 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
892 		if (wpa_s->dbus_new_path)
893 			paths[i++] = wpa_s->dbus_new_path;
894 	}
895 
896 	success = wpas_dbus_simple_array_property_getter(iter,
897 							 DBUS_TYPE_OBJECT_PATH,
898 							 paths, num, error);
899 
900 	os_free(paths);
901 	return success;
902 }
903 
904 
905 /**
906  * wpas_dbus_getter_eap_methods - Request supported EAP methods list
907  * @iter: Pointer to incoming dbus message iter
908  * @error: Location to store error on failure
909  * @user_data: Function specific data
910  * Returns: TRUE on success, FALSE on failure
911  *
912  * Getter for "EapMethods" property. Handles requests
913  * by dbus clients to return list of strings with supported EAP methods
914  */
wpas_dbus_getter_eap_methods(DBusMessageIter * iter,DBusError * error,void * user_data)915 dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
916 					 DBusError *error, void *user_data)
917 {
918 	char **eap_methods;
919 	size_t num_items = 0;
920 	dbus_bool_t success;
921 
922 	eap_methods = eap_get_names_as_string_array(&num_items);
923 	if (!eap_methods) {
924 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
925 		return FALSE;
926 	}
927 
928 	success = wpas_dbus_simple_array_property_getter(iter,
929 							 DBUS_TYPE_STRING,
930 							 eap_methods,
931 							 num_items, error);
932 
933 	while (num_items)
934 		os_free(eap_methods[--num_items]);
935 	os_free(eap_methods);
936 	return success;
937 }
938 
939 
940 /**
941  * wpas_dbus_getter_global_capabilities - Request supported global capabilities
942  * @iter: Pointer to incoming dbus message iter
943  * @error: Location to store error on failure
944  * @user_data: Function specific data
945  * Returns: TRUE on success, FALSE on failure
946  *
947  * Getter for "Capabilities" property. Handles requests by dbus clients to
948  * return a list of strings with supported capabilities like AP, RSN IBSS,
949  * and P2P that are determined at compile time.
950  */
wpas_dbus_getter_global_capabilities(DBusMessageIter * iter,DBusError * error,void * user_data)951 dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
952 						 DBusError *error,
953 						 void *user_data)
954 {
955 	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
956 	size_t num_items = 0;
957 
958 #ifdef CONFIG_AP
959 	capabilities[num_items++] = "ap";
960 #endif /* CONFIG_AP */
961 #ifdef CONFIG_IBSS_RSN
962 	capabilities[num_items++] = "ibss-rsn";
963 #endif /* CONFIG_IBSS_RSN */
964 #ifdef CONFIG_P2P
965 	capabilities[num_items++] = "p2p";
966 #endif /* CONFIG_P2P */
967 #ifdef CONFIG_INTERWORKING
968 	capabilities[num_items++] = "interworking";
969 #endif /* CONFIG_INTERWORKING */
970 
971 	return wpas_dbus_simple_array_property_getter(iter,
972 						      DBUS_TYPE_STRING,
973 						      capabilities,
974 						      num_items, error);
975 }
976 
977 
wpas_dbus_get_scan_type(DBusMessage * message,DBusMessageIter * var,char ** type,DBusMessage ** reply)978 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
979 				   char **type, DBusMessage **reply)
980 {
981 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
982 		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
983 			   __func__);
984 		*reply = wpas_dbus_error_invalid_args(
985 			message, "Wrong Type value type. String required");
986 		return -1;
987 	}
988 	dbus_message_iter_get_basic(var, type);
989 	return 0;
990 }
991 
992 
wpas_dbus_get_scan_ssids(DBusMessage * message,DBusMessageIter * var,struct wpa_driver_scan_params * params,DBusMessage ** reply)993 static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
994 				    struct wpa_driver_scan_params *params,
995 				    DBusMessage **reply)
996 {
997 	struct wpa_driver_scan_ssid *ssids = params->ssids;
998 	size_t ssids_num = 0;
999 	u8 *ssid;
1000 	DBusMessageIter array_iter, sub_array_iter;
1001 	char *val;
1002 	int len;
1003 
1004 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1005 		wpa_printf(MSG_DEBUG,
1006 			   "%s[dbus]: ssids must be an array of arrays of bytes",
1007 			   __func__);
1008 		*reply = wpas_dbus_error_invalid_args(
1009 			message,
1010 			"Wrong SSIDs value type. Array of arrays of bytes required");
1011 		return -1;
1012 	}
1013 
1014 	dbus_message_iter_recurse(var, &array_iter);
1015 
1016 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1017 	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1018 		wpa_printf(MSG_DEBUG,
1019 			   "%s[dbus]: ssids must be an array of arrays of bytes",
1020 			   __func__);
1021 		*reply = wpas_dbus_error_invalid_args(
1022 			message,
1023 			"Wrong SSIDs value type. Array of arrays of bytes required");
1024 		return -1;
1025 	}
1026 
1027 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
1028 		if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
1029 			wpa_printf(MSG_DEBUG,
1030 				   "%s[dbus]: Too many ssids specified on scan dbus call",
1031 				   __func__);
1032 			*reply = wpas_dbus_error_invalid_args(
1033 				message,
1034 				"Too many ssids specified. Specify at most four");
1035 			return -1;
1036 		}
1037 
1038 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1039 
1040 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1041 
1042 		if (len > SSID_MAX_LEN) {
1043 			wpa_printf(MSG_DEBUG,
1044 				   "%s[dbus]: SSID too long (len=%d max_len=%d)",
1045 				   __func__, len, SSID_MAX_LEN);
1046 			*reply = wpas_dbus_error_invalid_args(
1047 				message, "Invalid SSID: too long");
1048 			return -1;
1049 		}
1050 
1051 		if (len != 0) {
1052 			ssid = os_malloc(len);
1053 			if (ssid == NULL) {
1054 				*reply = wpas_dbus_error_no_memory(message);
1055 				return -1;
1056 			}
1057 			os_memcpy(ssid, val, len);
1058 		} else {
1059 			/* Allow zero-length SSIDs */
1060 			ssid = NULL;
1061 		}
1062 
1063 		ssids[ssids_num].ssid = ssid;
1064 		ssids[ssids_num].ssid_len = len;
1065 
1066 		dbus_message_iter_next(&array_iter);
1067 		ssids_num++;
1068 	}
1069 
1070 	params->num_ssids = ssids_num;
1071 	return 0;
1072 }
1073 
1074 
wpas_dbus_get_scan_ies(DBusMessage * message,DBusMessageIter * var,struct wpa_driver_scan_params * params,DBusMessage ** reply)1075 static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
1076 				  struct wpa_driver_scan_params *params,
1077 				  DBusMessage **reply)
1078 {
1079 	u8 *ies = NULL, *nies;
1080 	int ies_len = 0;
1081 	DBusMessageIter array_iter, sub_array_iter;
1082 	char *val;
1083 	int len;
1084 
1085 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1086 		wpa_printf(MSG_DEBUG,
1087 			   "%s[dbus]: ies must be an array of arrays of bytes",
1088 			   __func__);
1089 		*reply = wpas_dbus_error_invalid_args(
1090 			message,
1091 			"Wrong IEs value type. Array of arrays of bytes required");
1092 		return -1;
1093 	}
1094 
1095 	dbus_message_iter_recurse(var, &array_iter);
1096 
1097 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1098 	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1099 		wpa_printf(MSG_DEBUG,
1100 			   "%s[dbus]: ies must be an array of arrays of bytes",
1101 			   __func__);
1102 		*reply = wpas_dbus_error_invalid_args(
1103 			message, "Wrong IEs value type. Array required");
1104 		return -1;
1105 	}
1106 
1107 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
1108 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1109 
1110 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1111 		if (len == 0) {
1112 			dbus_message_iter_next(&array_iter);
1113 			continue;
1114 		}
1115 
1116 		nies = os_realloc(ies, ies_len + len);
1117 		if (nies == NULL) {
1118 			os_free(ies);
1119 			*reply = wpas_dbus_error_no_memory(message);
1120 			return -1;
1121 		}
1122 		ies = nies;
1123 		os_memcpy(ies + ies_len, val, len);
1124 		ies_len += len;
1125 
1126 		dbus_message_iter_next(&array_iter);
1127 	}
1128 
1129 	params->extra_ies = ies;
1130 	params->extra_ies_len = ies_len;
1131 	return 0;
1132 }
1133 
1134 
wpas_dbus_get_scan_channels(DBusMessage * message,DBusMessageIter * var,struct wpa_driver_scan_params * params,DBusMessage ** reply)1135 static int wpas_dbus_get_scan_channels(DBusMessage *message,
1136 				       DBusMessageIter *var,
1137 				       struct wpa_driver_scan_params *params,
1138 				       DBusMessage **reply)
1139 {
1140 	DBusMessageIter array_iter, sub_array_iter;
1141 	int *freqs = NULL, *nfreqs;
1142 	int freqs_num = 0;
1143 
1144 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1145 		wpa_printf(MSG_DEBUG,
1146 			   "%s[dbus]: Channels must be an array of structs",
1147 			   __func__);
1148 		*reply = wpas_dbus_error_invalid_args(
1149 			message,
1150 			"Wrong Channels value type. Array of structs required");
1151 		return -1;
1152 	}
1153 
1154 	dbus_message_iter_recurse(var, &array_iter);
1155 
1156 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
1157 		wpa_printf(MSG_DEBUG,
1158 			   "%s[dbus]: Channels must be an array of structs",
1159 			   __func__);
1160 		*reply = wpas_dbus_error_invalid_args(
1161 			message,
1162 			"Wrong Channels value type. Array of structs required");
1163 		return -1;
1164 	}
1165 
1166 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
1167 	{
1168 		int freq, width;
1169 
1170 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1171 
1172 		if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
1173 		    DBUS_TYPE_UINT32) {
1174 			wpa_printf(MSG_DEBUG,
1175 				   "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
1176 				   __func__,
1177 				   dbus_message_iter_get_arg_type(
1178 					   &sub_array_iter));
1179 			*reply = wpas_dbus_error_invalid_args(
1180 				message,
1181 				"Wrong Channel struct. Two UINT32s required");
1182 			os_free(freqs);
1183 			return -1;
1184 		}
1185 		dbus_message_iter_get_basic(&sub_array_iter, &freq);
1186 
1187 		if (!dbus_message_iter_next(&sub_array_iter) ||
1188 		    dbus_message_iter_get_arg_type(&sub_array_iter) !=
1189 		    DBUS_TYPE_UINT32) {
1190 			wpa_printf(MSG_DEBUG,
1191 				   "%s[dbus]: Channel must by specified by struct of two UINT32s",
1192 				   __func__);
1193 			*reply = wpas_dbus_error_invalid_args(
1194 				message,
1195 				"Wrong Channel struct. Two UINT32s required");
1196 			os_free(freqs);
1197 			return -1;
1198 		}
1199 
1200 		dbus_message_iter_get_basic(&sub_array_iter, &width);
1201 
1202 #define FREQS_ALLOC_CHUNK 32
1203 		if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
1204 			nfreqs = os_realloc_array(
1205 				freqs, freqs_num + FREQS_ALLOC_CHUNK,
1206 				sizeof(int));
1207 			if (nfreqs == NULL)
1208 				os_free(freqs);
1209 			freqs = nfreqs;
1210 		}
1211 		if (freqs == NULL) {
1212 			*reply = wpas_dbus_error_no_memory(message);
1213 			return -1;
1214 		}
1215 
1216 		freqs[freqs_num] = freq;
1217 
1218 		freqs_num++;
1219 		dbus_message_iter_next(&array_iter);
1220 	}
1221 
1222 	nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
1223 	if (nfreqs == NULL)
1224 		os_free(freqs);
1225 	freqs = nfreqs;
1226 	if (freqs == NULL) {
1227 		*reply = wpas_dbus_error_no_memory(message);
1228 		return -1;
1229 	}
1230 	freqs[freqs_num] = 0;
1231 
1232 	params->freqs = freqs;
1233 	return 0;
1234 }
1235 
1236 
wpas_dbus_get_scan_allow_roam(DBusMessage * message,DBusMessageIter * var,dbus_bool_t * allow,DBusMessage ** reply)1237 static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
1238 					 DBusMessageIter *var,
1239 					 dbus_bool_t *allow,
1240 					 DBusMessage **reply)
1241 {
1242 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
1243 		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
1244 			   __func__);
1245 		*reply = wpas_dbus_error_invalid_args(
1246 			message, "Wrong Type value type. Boolean required");
1247 		return -1;
1248 	}
1249 	dbus_message_iter_get_basic(var, allow);
1250 	return 0;
1251 }
1252 
1253 
1254 /**
1255  * wpas_dbus_handler_scan - Request a wireless scan on an interface
1256  * @message: Pointer to incoming dbus message
1257  * @wpa_s: wpa_supplicant structure for a network interface
1258  * Returns: NULL indicating success or DBus error message on failure
1259  *
1260  * Handler function for "Scan" method call of a network device. Requests
1261  * that wpa_supplicant perform a wireless scan as soon as possible
1262  * on a particular wireless interface.
1263  */
wpas_dbus_handler_scan(DBusMessage * message,struct wpa_supplicant * wpa_s)1264 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
1265 				     struct wpa_supplicant *wpa_s)
1266 {
1267 	DBusMessage *reply = NULL;
1268 	DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
1269 	char *key = NULL, *type = NULL;
1270 	struct wpa_driver_scan_params params;
1271 	size_t i;
1272 	dbus_bool_t allow_roam = 1;
1273 
1274 	os_memset(&params, 0, sizeof(params));
1275 
1276 	dbus_message_iter_init(message, &iter);
1277 
1278 	dbus_message_iter_recurse(&iter, &dict_iter);
1279 
1280 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
1281 	       DBUS_TYPE_DICT_ENTRY) {
1282 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
1283 		dbus_message_iter_get_basic(&entry_iter, &key);
1284 		dbus_message_iter_next(&entry_iter);
1285 		dbus_message_iter_recurse(&entry_iter, &variant_iter);
1286 
1287 		if (os_strcmp(key, "Type") == 0) {
1288 			if (wpas_dbus_get_scan_type(message, &variant_iter,
1289 						    &type, &reply) < 0)
1290 				goto out;
1291 		} else if (os_strcmp(key, "SSIDs") == 0) {
1292 			if (wpas_dbus_get_scan_ssids(message, &variant_iter,
1293 						     &params, &reply) < 0)
1294 				goto out;
1295 		} else if (os_strcmp(key, "IEs") == 0) {
1296 			if (wpas_dbus_get_scan_ies(message, &variant_iter,
1297 						   &params, &reply) < 0)
1298 				goto out;
1299 		} else if (os_strcmp(key, "Channels") == 0) {
1300 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
1301 							&params, &reply) < 0)
1302 				goto out;
1303 		} else if (os_strcmp(key, "AllowRoam") == 0) {
1304 			if (wpas_dbus_get_scan_allow_roam(message,
1305 							  &variant_iter,
1306 							  &allow_roam,
1307 							  &reply) < 0)
1308 				goto out;
1309 		} else {
1310 			wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
1311 				   __func__, key);
1312 			reply = wpas_dbus_error_invalid_args(message, key);
1313 			goto out;
1314 		}
1315 
1316 		dbus_message_iter_next(&dict_iter);
1317 	}
1318 
1319 	if (!type) {
1320 		wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
1321 			   __func__);
1322 		reply = wpas_dbus_error_invalid_args(message, key);
1323 		goto out;
1324 	}
1325 
1326 	if (os_strcmp(type, "passive") == 0) {
1327 		if (params.num_ssids || params.extra_ies_len) {
1328 			wpa_printf(MSG_DEBUG,
1329 				   "%s[dbus]: SSIDs or IEs specified for passive scan.",
1330 				   __func__);
1331 			reply = wpas_dbus_error_invalid_args(
1332 				message,
1333 				"You can specify only Channels in passive scan");
1334 			goto out;
1335 		} else {
1336 			if (wpa_s->sched_scanning) {
1337 				wpa_printf(MSG_DEBUG,
1338 					   "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1339 					   __func__);
1340 				wpa_supplicant_cancel_sched_scan(wpa_s);
1341 			}
1342 
1343 			if (params.freqs && params.freqs[0]) {
1344 				if (wpa_supplicant_trigger_scan(wpa_s,
1345 								&params)) {
1346 					reply = wpas_dbus_error_scan_error(
1347 						message,
1348 						"Scan request rejected");
1349 				}
1350 			} else {
1351 				wpa_s->scan_req = MANUAL_SCAN_REQ;
1352 				wpa_supplicant_req_scan(wpa_s, 0, 0);
1353 			}
1354 		}
1355 	} else if (os_strcmp(type, "active") == 0) {
1356 		if (!params.num_ssids) {
1357 			/* Add wildcard ssid */
1358 			params.num_ssids++;
1359 		}
1360 #ifdef CONFIG_AUTOSCAN
1361 		autoscan_deinit(wpa_s);
1362 #endif /* CONFIG_AUTOSCAN */
1363 		if (wpa_s->sched_scanning) {
1364 			wpa_printf(MSG_DEBUG,
1365 				   "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1366 				   __func__);
1367 			wpa_supplicant_cancel_sched_scan(wpa_s);
1368 		}
1369 
1370 		if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1371 			reply = wpas_dbus_error_scan_error(
1372 				message, "Scan request rejected");
1373 		}
1374 	} else {
1375 		wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
1376 			   __func__, type);
1377 		reply = wpas_dbus_error_invalid_args(message,
1378 						     "Wrong scan type");
1379 		goto out;
1380 	}
1381 
1382 	if (!allow_roam)
1383 		wpa_s->scan_res_handler = scan_only_handler;
1384 
1385 out:
1386 	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
1387 		os_free((u8 *) params.ssids[i].ssid);
1388 	os_free((u8 *) params.extra_ies);
1389 	os_free(params.freqs);
1390 	return reply;
1391 }
1392 
1393 
1394 /**
1395  * wpas_dbus_handler_signal_poll - Request immediate signal properties
1396  * @message: Pointer to incoming dbus message
1397  * @wpa_s: wpa_supplicant structure for a network interface
1398  * Returns: NULL indicating success or DBus error message on failure
1399  *
1400  * Handler function for "SignalPoll" method call of a network device. Requests
1401  * that wpa_supplicant read signal properties like RSSI, noise, and link
1402  * speed and return them.
1403  */
wpas_dbus_handler_signal_poll(DBusMessage * message,struct wpa_supplicant * wpa_s)1404 DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
1405 					    struct wpa_supplicant *wpa_s)
1406 {
1407 	struct wpa_signal_info si;
1408 	DBusMessage *reply = NULL;
1409 	DBusMessageIter iter, iter_dict, variant_iter;
1410 	int ret;
1411 
1412 	ret = wpa_drv_signal_poll(wpa_s, &si);
1413 	if (ret) {
1414 		return dbus_message_new_error(message, DBUS_ERROR_FAILED,
1415 					      "Failed to read signal");
1416 	}
1417 
1418 	reply = dbus_message_new_method_return(message);
1419 	if (reply == NULL)
1420 		goto nomem;
1421 
1422 	dbus_message_iter_init_append(reply, &iter);
1423 
1424 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1425 					      "a{sv}", &variant_iter) ||
1426 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
1427 	    !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
1428 					si.current_signal) ||
1429 	    !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
1430 					si.current_txrate / 1000) ||
1431 	    !wpa_dbus_dict_append_int32(&iter_dict, "noise",
1432 					si.current_noise) ||
1433 	    !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
1434 					 si.frequency) ||
1435 	    (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
1436 	     !wpa_dbus_dict_append_string(
1437 		     &iter_dict, "width",
1438 		     channel_width_to_string(si.chanwidth))) ||
1439 	    (si.center_frq1 > 0 && si.center_frq2 > 0 &&
1440 	     (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
1441 					  si.center_frq1) ||
1442 	      !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
1443 					  si.center_frq2))) ||
1444 	    (si.avg_signal &&
1445 	     !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
1446 					 si.avg_signal)) ||
1447 	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
1448 	    !dbus_message_iter_close_container(&iter, &variant_iter))
1449 		goto nomem;
1450 
1451 	return reply;
1452 
1453 nomem:
1454 	if (reply)
1455 		dbus_message_unref(reply);
1456 	return wpas_dbus_error_no_memory(message);
1457 }
1458 
1459 
1460 /*
1461  * wpas_dbus_handler_disconnect - Terminate the current connection
1462  * @message: Pointer to incoming dbus message
1463  * @wpa_s: wpa_supplicant structure for a network interface
1464  * Returns: NotConnected DBus error message if already not connected
1465  * or NULL otherwise.
1466  *
1467  * Handler function for "Disconnect" method call of network interface.
1468  */
wpas_dbus_handler_disconnect(DBusMessage * message,struct wpa_supplicant * wpa_s)1469 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
1470 					   struct wpa_supplicant *wpa_s)
1471 {
1472 	if (wpa_s->current_ssid != NULL) {
1473 		wpa_s->disconnected = 1;
1474 		wpa_supplicant_deauthenticate(wpa_s,
1475 					      WLAN_REASON_DEAUTH_LEAVING);
1476 
1477 		return NULL;
1478 	}
1479 
1480 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1481 				      "This interface is not connected");
1482 }
1483 
1484 
1485 /**
1486  * wpas_dbus_new_iface_add_network - Add a new configured network
1487  * @message: Pointer to incoming dbus message
1488  * @wpa_s: wpa_supplicant structure for a network interface
1489  * Returns: A dbus message containing the object path of the new network
1490  *
1491  * Handler function for "AddNetwork" method call of a network interface.
1492  */
wpas_dbus_handler_add_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1493 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
1494 					    struct wpa_supplicant *wpa_s)
1495 {
1496 	DBusMessage *reply = NULL;
1497 	DBusMessageIter	iter;
1498 	struct wpa_ssid *ssid = NULL;
1499 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1500 	DBusError error;
1501 
1502 	dbus_message_iter_init(message, &iter);
1503 
1504 	if (wpa_s->dbus_new_path)
1505 		ssid = wpa_config_add_network(wpa_s->conf);
1506 	if (ssid == NULL) {
1507 		wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
1508 			   __func__);
1509 		reply = wpas_dbus_error_unknown_error(
1510 			message,
1511 			"wpa_supplicant could not add a network on this interface.");
1512 		goto err;
1513 	}
1514 	wpas_notify_network_added(wpa_s, ssid);
1515 	ssid->disabled = 1;
1516 	wpa_config_set_network_defaults(ssid);
1517 
1518 	dbus_error_init(&error);
1519 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1520 		wpa_printf(MSG_DEBUG,
1521 			   "%s[dbus]: control interface couldn't set network properties",
1522 			   __func__);
1523 		reply = wpas_dbus_reply_new_from_error(message, &error,
1524 						       DBUS_ERROR_INVALID_ARGS,
1525 						       "Failed to add network");
1526 		dbus_error_free(&error);
1527 		goto err;
1528 	}
1529 
1530 	/* Construct the object path for this network. */
1531 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1532 		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
1533 		    wpa_s->dbus_new_path, ssid->id);
1534 
1535 	reply = dbus_message_new_method_return(message);
1536 	if (reply == NULL) {
1537 		reply = wpas_dbus_error_no_memory(message);
1538 		goto err;
1539 	}
1540 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1541 				      DBUS_TYPE_INVALID)) {
1542 		dbus_message_unref(reply);
1543 		reply = wpas_dbus_error_no_memory(message);
1544 		goto err;
1545 	}
1546 
1547 	return reply;
1548 
1549 err:
1550 	if (ssid) {
1551 		wpas_notify_network_removed(wpa_s, ssid);
1552 		wpa_config_remove_network(wpa_s->conf, ssid->id);
1553 	}
1554 	return reply;
1555 }
1556 
1557 
1558 /**
1559  * wpas_dbus_handler_reassociate - Reassociate
1560  * @message: Pointer to incoming dbus message
1561  * @wpa_s: wpa_supplicant structure for a network interface
1562  * Returns: InterfaceDisabled DBus error message if disabled
1563  * or NULL otherwise.
1564  *
1565  * Handler function for "Reassociate" method call of network interface.
1566  */
wpas_dbus_handler_reassociate(DBusMessage * message,struct wpa_supplicant * wpa_s)1567 DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
1568 					    struct wpa_supplicant *wpa_s)
1569 {
1570 	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
1571 		wpas_request_connection(wpa_s);
1572 		return NULL;
1573 	}
1574 
1575 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
1576 				      "This interface is disabled");
1577 }
1578 
1579 
1580 /**
1581  * wpas_dbus_handler_reattach - Reattach to current AP
1582  * @message: Pointer to incoming dbus message
1583  * @wpa_s: wpa_supplicant structure for a network interface
1584  * Returns: NotConnected DBus error message if not connected
1585  * or NULL otherwise.
1586  *
1587  * Handler function for "Reattach" method call of network interface.
1588  */
wpas_dbus_handler_reattach(DBusMessage * message,struct wpa_supplicant * wpa_s)1589 DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
1590 					 struct wpa_supplicant *wpa_s)
1591 {
1592 	if (wpa_s->current_ssid != NULL) {
1593 		wpa_s->reattach = 1;
1594 		wpas_request_connection(wpa_s);
1595 		return NULL;
1596 	}
1597 
1598 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1599 				      "This interface is not connected");
1600 }
1601 
1602 
1603 /**
1604  * wpas_dbus_handler_reconnect - Reconnect if disconnected
1605  * @message: Pointer to incoming dbus message
1606  * @wpa_s: wpa_supplicant structure for a network interface
1607  * Returns: InterfaceDisabled DBus error message if disabled
1608  * or NULL otherwise.
1609  *
1610  * Handler function for "Reconnect" method call of network interface.
1611  */
wpas_dbus_handler_reconnect(DBusMessage * message,struct wpa_supplicant * wpa_s)1612 DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
1613 		struct wpa_supplicant *wpa_s)
1614 {
1615 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
1616 		return dbus_message_new_error(message,
1617 					      WPAS_DBUS_ERROR_IFACE_DISABLED,
1618 					      "This interface is disabled");
1619 	}
1620 
1621 	if (wpa_s->disconnected)
1622 		wpas_request_connection(wpa_s);
1623 	return NULL;
1624 }
1625 
1626 
1627 /**
1628  * wpas_dbus_handler_remove_network - Remove a configured network
1629  * @message: Pointer to incoming dbus message
1630  * @wpa_s: wpa_supplicant structure for a network interface
1631  * Returns: NULL on success or dbus error on failure
1632  *
1633  * Handler function for "RemoveNetwork" method call of a network interface.
1634  */
wpas_dbus_handler_remove_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1635 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
1636 					       struct wpa_supplicant *wpa_s)
1637 {
1638 	DBusMessage *reply = NULL;
1639 	const char *op;
1640 	char *iface, *net_id;
1641 	int id;
1642 	struct wpa_ssid *ssid;
1643 	int was_disabled;
1644 
1645 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1646 			      DBUS_TYPE_INVALID);
1647 
1648 	/* Extract the network ID and ensure the network */
1649 	/* is actually a child of this interface */
1650 	iface = wpas_dbus_new_decompose_object_path(op,
1651 						    WPAS_DBUS_NEW_NETWORKS_PART,
1652 						    &net_id);
1653 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1654 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1655 		reply = wpas_dbus_error_invalid_args(message, op);
1656 		goto out;
1657 	}
1658 
1659 	errno = 0;
1660 	id = strtoul(net_id, NULL, 10);
1661 	if (errno != 0) {
1662 		reply = wpas_dbus_error_invalid_args(message, op);
1663 		goto out;
1664 	}
1665 
1666 	ssid = wpa_config_get_network(wpa_s->conf, id);
1667 	if (ssid == NULL) {
1668 		reply = wpas_dbus_error_network_unknown(message);
1669 		goto out;
1670 	}
1671 
1672 	was_disabled = ssid->disabled;
1673 
1674 	wpas_notify_network_removed(wpa_s, ssid);
1675 
1676 	if (ssid == wpa_s->current_ssid)
1677 		wpa_supplicant_deauthenticate(wpa_s,
1678 					      WLAN_REASON_DEAUTH_LEAVING);
1679 	else if (!was_disabled && wpa_s->sched_scanning) {
1680 		wpa_printf(MSG_DEBUG,
1681 			   "Stop ongoing sched_scan to remove network from filters");
1682 		wpa_supplicant_cancel_sched_scan(wpa_s);
1683 		wpa_supplicant_req_scan(wpa_s, 0, 0);
1684 	}
1685 
1686 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1687 		wpa_printf(MSG_ERROR,
1688 			   "%s[dbus]: error occurred when removing network %d",
1689 			   __func__, id);
1690 		reply = wpas_dbus_error_unknown_error(
1691 			message,
1692 			"error removing the specified network on is interface.");
1693 		goto out;
1694 	}
1695 
1696 out:
1697 	os_free(iface);
1698 	return reply;
1699 }
1700 
1701 
remove_network(void * arg,struct wpa_ssid * ssid)1702 static void remove_network(void *arg, struct wpa_ssid *ssid)
1703 {
1704 	struct wpa_supplicant *wpa_s = arg;
1705 
1706 	wpas_notify_network_removed(wpa_s, ssid);
1707 
1708 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1709 		wpa_printf(MSG_ERROR,
1710 			   "%s[dbus]: error occurred when removing network %d",
1711 			   __func__, ssid->id);
1712 		return;
1713 	}
1714 
1715 	if (ssid == wpa_s->current_ssid)
1716 		wpa_supplicant_deauthenticate(wpa_s,
1717 					      WLAN_REASON_DEAUTH_LEAVING);
1718 }
1719 
1720 
1721 /**
1722  * wpas_dbus_handler_remove_all_networks - Remove all configured networks
1723  * @message: Pointer to incoming dbus message
1724  * @wpa_s: wpa_supplicant structure for a network interface
1725  * Returns: NULL on success or dbus error on failure
1726  *
1727  * Handler function for "RemoveAllNetworks" method call of a network interface.
1728  */
wpas_dbus_handler_remove_all_networks(DBusMessage * message,struct wpa_supplicant * wpa_s)1729 DBusMessage * wpas_dbus_handler_remove_all_networks(
1730 	DBusMessage *message, struct wpa_supplicant *wpa_s)
1731 {
1732 	if (wpa_s->sched_scanning)
1733 		wpa_supplicant_cancel_sched_scan(wpa_s);
1734 
1735 	/* NB: could check for failure and return an error */
1736 	wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
1737 	return NULL;
1738 }
1739 
1740 
1741 /**
1742  * wpas_dbus_handler_select_network - Attempt association with a network
1743  * @message: Pointer to incoming dbus message
1744  * @wpa_s: wpa_supplicant structure for a network interface
1745  * Returns: NULL on success or dbus error on failure
1746  *
1747  * Handler function for "SelectNetwork" method call of network interface.
1748  */
wpas_dbus_handler_select_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1749 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
1750 					       struct wpa_supplicant *wpa_s)
1751 {
1752 	DBusMessage *reply = NULL;
1753 	const char *op;
1754 	char *iface, *net_id;
1755 	int id;
1756 	struct wpa_ssid *ssid;
1757 
1758 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1759 			      DBUS_TYPE_INVALID);
1760 
1761 	/* Extract the network ID and ensure the network */
1762 	/* is actually a child of this interface */
1763 	iface = wpas_dbus_new_decompose_object_path(op,
1764 						    WPAS_DBUS_NEW_NETWORKS_PART,
1765 						    &net_id);
1766 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1767 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1768 		reply = wpas_dbus_error_invalid_args(message, op);
1769 		goto out;
1770 	}
1771 
1772 	errno = 0;
1773 	id = strtoul(net_id, NULL, 10);
1774 	if (errno != 0) {
1775 		reply = wpas_dbus_error_invalid_args(message, op);
1776 		goto out;
1777 	}
1778 
1779 	ssid = wpa_config_get_network(wpa_s->conf, id);
1780 	if (ssid == NULL) {
1781 		reply = wpas_dbus_error_network_unknown(message);
1782 		goto out;
1783 	}
1784 
1785 	/* Finally, associate with the network */
1786 	wpa_supplicant_select_network(wpa_s, ssid);
1787 
1788 out:
1789 	os_free(iface);
1790 	return reply;
1791 }
1792 
1793 
1794 /**
1795  * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
1796  * @message: Pointer to incoming dbus message
1797  * @wpa_s: wpa_supplicant structure for a network interface
1798  * Returns: NULL on success or dbus error on failure
1799  *
1800  * Handler function for "NetworkReply" method call of network interface.
1801  */
wpas_dbus_handler_network_reply(DBusMessage * message,struct wpa_supplicant * wpa_s)1802 DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
1803 					      struct wpa_supplicant *wpa_s)
1804 {
1805 #ifdef IEEE8021X_EAPOL
1806 	DBusMessage *reply = NULL;
1807 	const char *op, *field, *value;
1808 	char *iface, *net_id;
1809 	int id;
1810 	struct wpa_ssid *ssid;
1811 
1812 	if (!dbus_message_get_args(message, NULL,
1813 				   DBUS_TYPE_OBJECT_PATH, &op,
1814 				   DBUS_TYPE_STRING, &field,
1815 				   DBUS_TYPE_STRING, &value,
1816 				   DBUS_TYPE_INVALID))
1817 		return wpas_dbus_error_invalid_args(message, NULL);
1818 
1819 	/* Extract the network ID and ensure the network */
1820 	/* is actually a child of this interface */
1821 	iface = wpas_dbus_new_decompose_object_path(op,
1822 						    WPAS_DBUS_NEW_NETWORKS_PART,
1823 						    &net_id);
1824 	if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1825 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1826 		reply = wpas_dbus_error_invalid_args(message, op);
1827 		goto out;
1828 	}
1829 
1830 	errno = 0;
1831 	id = strtoul(net_id, NULL, 10);
1832 	if (errno != 0) {
1833 		reply = wpas_dbus_error_invalid_args(message, net_id);
1834 		goto out;
1835 	}
1836 
1837 	ssid = wpa_config_get_network(wpa_s->conf, id);
1838 	if (ssid == NULL) {
1839 		reply = wpas_dbus_error_network_unknown(message);
1840 		goto out;
1841 	}
1842 
1843 	if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
1844 						      field, value) < 0)
1845 		reply = wpas_dbus_error_invalid_args(message, field);
1846 	else {
1847 		/* Tell EAP to retry immediately */
1848 		eapol_sm_notify_ctrl_response(wpa_s->eapol);
1849 	}
1850 
1851 out:
1852 	os_free(iface);
1853 	return reply;
1854 #else /* IEEE8021X_EAPOL */
1855 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1856 	return wpas_dbus_error_unknown_error(message, "802.1X not included");
1857 #endif /* IEEE8021X_EAPOL */
1858 }
1859 
1860 
1861 #ifndef CONFIG_NO_CONFIG_BLOBS
1862 
1863 /**
1864  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
1865  * @message: Pointer to incoming dbus message
1866  * @wpa_s: %wpa_supplicant data structure
1867  * Returns: A dbus message containing an error on failure or NULL on success
1868  *
1869  * Asks wpa_supplicant to internally store a binary blobs.
1870  */
wpas_dbus_handler_add_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)1871 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
1872 					 struct wpa_supplicant *wpa_s)
1873 {
1874 	DBusMessage *reply = NULL;
1875 	DBusMessageIter	iter, array_iter;
1876 
1877 	char *blob_name;
1878 	u8 *blob_data;
1879 	int blob_len;
1880 	struct wpa_config_blob *blob = NULL;
1881 
1882 	dbus_message_iter_init(message, &iter);
1883 	dbus_message_iter_get_basic(&iter, &blob_name);
1884 
1885 	if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
1886 		return dbus_message_new_error(message,
1887 					      WPAS_DBUS_ERROR_BLOB_EXISTS,
1888 					      NULL);
1889 	}
1890 
1891 	dbus_message_iter_next(&iter);
1892 	dbus_message_iter_recurse(&iter, &array_iter);
1893 
1894 	dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
1895 
1896 	blob = os_zalloc(sizeof(*blob));
1897 	if (!blob) {
1898 		reply = wpas_dbus_error_no_memory(message);
1899 		goto err;
1900 	}
1901 
1902 	blob->data = os_malloc(blob_len);
1903 	blob->name = os_strdup(blob_name);
1904 	if (!blob->data || !blob->name) {
1905 		reply = wpas_dbus_error_no_memory(message);
1906 		goto err;
1907 	}
1908 	os_memcpy(blob->data, blob_data, blob_len);
1909 	blob->len = blob_len;
1910 
1911 	wpa_config_set_blob(wpa_s->conf, blob);
1912 	wpas_notify_blob_added(wpa_s, blob->name);
1913 
1914 	return reply;
1915 
1916 err:
1917 	if (blob) {
1918 		os_free(blob->name);
1919 		os_free(blob->data);
1920 		os_free(blob);
1921 	}
1922 	return reply;
1923 }
1924 
1925 
1926 /**
1927  * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
1928  * @message: Pointer to incoming dbus message
1929  * @wpa_s: %wpa_supplicant data structure
1930  * Returns: A dbus message containing array of bytes (blob)
1931  *
1932  * Gets one wpa_supplicant's binary blobs.
1933  */
wpas_dbus_handler_get_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)1934 DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
1935 					 struct wpa_supplicant *wpa_s)
1936 {
1937 	DBusMessage *reply = NULL;
1938 	DBusMessageIter	iter, array_iter;
1939 
1940 	char *blob_name;
1941 	const struct wpa_config_blob *blob;
1942 
1943 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1944 			      DBUS_TYPE_INVALID);
1945 
1946 	blob = wpa_config_get_blob(wpa_s->conf, blob_name);
1947 	if (!blob) {
1948 		return dbus_message_new_error(message,
1949 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1950 					      "Blob id not set");
1951 	}
1952 
1953 	reply = dbus_message_new_method_return(message);
1954 	if (!reply)
1955 		return wpas_dbus_error_no_memory(message);
1956 
1957 	dbus_message_iter_init_append(reply, &iter);
1958 
1959 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1960 					      DBUS_TYPE_BYTE_AS_STRING,
1961 					      &array_iter) ||
1962 	    !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
1963 						  &(blob->data), blob->len) ||
1964 	    !dbus_message_iter_close_container(&iter, &array_iter)) {
1965 		dbus_message_unref(reply);
1966 		reply = wpas_dbus_error_no_memory(message);
1967 	}
1968 
1969 	return reply;
1970 }
1971 
1972 
1973 /**
1974  * wpas_remove_handler_remove_blob - Remove named binary blob
1975  * @message: Pointer to incoming dbus message
1976  * @wpa_s: %wpa_supplicant data structure
1977  * Returns: NULL on success or dbus error
1978  *
1979  * Asks wpa_supplicant to internally remove a binary blobs.
1980  */
wpas_dbus_handler_remove_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)1981 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
1982 					    struct wpa_supplicant *wpa_s)
1983 {
1984 	DBusMessage *reply = NULL;
1985 	char *blob_name;
1986 
1987 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1988 			      DBUS_TYPE_INVALID);
1989 
1990 	if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
1991 		return dbus_message_new_error(message,
1992 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1993 					      "Blob id not set");
1994 	}
1995 	wpas_notify_blob_removed(wpa_s, blob_name);
1996 
1997 	return reply;
1998 
1999 }
2000 
2001 #endif /* CONFIG_NO_CONFIG_BLOBS */
2002 
2003 
2004 /*
2005  * wpas_dbus_handler_flush_bss - Flush the BSS cache
2006  * @message: Pointer to incoming dbus message
2007  * @wpa_s: wpa_supplicant structure for a network interface
2008  * Returns: NULL
2009  *
2010  * Handler function for "FlushBSS" method call of network interface.
2011  */
wpas_dbus_handler_flush_bss(DBusMessage * message,struct wpa_supplicant * wpa_s)2012 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
2013 					  struct wpa_supplicant *wpa_s)
2014 {
2015 	dbus_uint32_t age;
2016 
2017 	dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
2018 			      DBUS_TYPE_INVALID);
2019 
2020 	if (age == 0)
2021 		wpa_bss_flush(wpa_s);
2022 	else
2023 		wpa_bss_flush_by_age(wpa_s, age);
2024 
2025 	return NULL;
2026 }
2027 
2028 
2029 #ifdef CONFIG_AUTOSCAN
2030 /**
2031  * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
2032  * @message: Pointer to incoming dbus message
2033  * @wpa_s: wpa_supplicant structure for a network interface
2034  * Returns: NULL
2035  *
2036  * Handler function for "AutoScan" method call of network interface.
2037  */
wpas_dbus_handler_autoscan(DBusMessage * message,struct wpa_supplicant * wpa_s)2038 DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
2039 					 struct wpa_supplicant *wpa_s)
2040 {
2041 	DBusMessage *reply = NULL;
2042 	enum wpa_states state = wpa_s->wpa_state;
2043 	char *arg;
2044 
2045 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
2046 			      DBUS_TYPE_INVALID);
2047 
2048 	if (arg != NULL && os_strlen(arg) > 0) {
2049 		char *tmp;
2050 
2051 		tmp = os_strdup(arg);
2052 		if (tmp == NULL) {
2053 			reply = wpas_dbus_error_no_memory(message);
2054 		} else {
2055 			os_free(wpa_s->conf->autoscan);
2056 			wpa_s->conf->autoscan = tmp;
2057 			if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
2058 				autoscan_init(wpa_s, 1);
2059 			else if (state == WPA_SCANNING)
2060 				wpa_supplicant_reinit_autoscan(wpa_s);
2061 		}
2062 	} else if (arg != NULL && os_strlen(arg) == 0) {
2063 		os_free(wpa_s->conf->autoscan);
2064 		wpa_s->conf->autoscan = NULL;
2065 		autoscan_deinit(wpa_s);
2066 	} else
2067 		reply = dbus_message_new_error(message,
2068 					       DBUS_ERROR_INVALID_ARGS,
2069 					       NULL);
2070 
2071 	return reply;
2072 }
2073 #endif /* CONFIG_AUTOSCAN */
2074 
2075 
2076 /*
2077  * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
2078  * @message: Pointer to incoming dbus message
2079  * @wpa_s: wpa_supplicant structure for a network interface
2080  * Returns: NULL
2081  *
2082  * Handler function for "EAPLogoff" method call of network interface.
2083  */
wpas_dbus_handler_eap_logoff(DBusMessage * message,struct wpa_supplicant * wpa_s)2084 DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
2085 					   struct wpa_supplicant *wpa_s)
2086 {
2087 	eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
2088 	return NULL;
2089 }
2090 
2091 
2092 /*
2093  * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
2094  * @message: Pointer to incoming dbus message
2095  * @wpa_s: wpa_supplicant structure for a network interface
2096  * Returns: NULL
2097  *
2098  * Handler function for "EAPLogin" method call of network interface.
2099  */
wpas_dbus_handler_eap_logon(DBusMessage * message,struct wpa_supplicant * wpa_s)2100 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
2101 					  struct wpa_supplicant *wpa_s)
2102 {
2103 	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
2104 	return NULL;
2105 }
2106 
2107 
2108 #ifdef CONFIG_TDLS
2109 
get_peer_hwaddr_helper(DBusMessage * message,const char * func_name,u8 * peer_address,DBusMessage ** error)2110 static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
2111 				  u8 *peer_address, DBusMessage **error)
2112 {
2113 	const char *peer_string;
2114 
2115 	*error = NULL;
2116 
2117 	if (!dbus_message_get_args(message, NULL,
2118 				   DBUS_TYPE_STRING, &peer_string,
2119 				   DBUS_TYPE_INVALID)) {
2120 		*error = wpas_dbus_error_invalid_args(message, NULL);
2121 		return -1;
2122 	}
2123 
2124 	if (hwaddr_aton(peer_string, peer_address)) {
2125 		wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
2126 			   func_name, peer_string);
2127 		*error = wpas_dbus_error_invalid_args(
2128 			message, "Invalid hardware address format");
2129 		return -1;
2130 	}
2131 
2132 	return 0;
2133 }
2134 
2135 
2136 /*
2137  * wpas_dbus_handler_tdls_discover - Discover TDLS peer
2138  * @message: Pointer to incoming dbus message
2139  * @wpa_s: wpa_supplicant structure for a network interface
2140  * Returns: NULL indicating success or DBus error message on failure
2141  *
2142  * Handler function for "TDLSDiscover" method call of network interface.
2143  */
wpas_dbus_handler_tdls_discover(DBusMessage * message,struct wpa_supplicant * wpa_s)2144 DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
2145 					      struct wpa_supplicant *wpa_s)
2146 {
2147 	u8 peer[ETH_ALEN];
2148 	DBusMessage *error_reply;
2149 	int ret;
2150 
2151 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2152 		return error_reply;
2153 
2154 	wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
2155 
2156 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2157 		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
2158 	else
2159 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
2160 
2161 	if (ret) {
2162 		return wpas_dbus_error_unknown_error(
2163 			message, "error performing TDLS discovery");
2164 	}
2165 
2166 	return NULL;
2167 }
2168 
2169 
2170 /*
2171  * wpas_dbus_handler_tdls_setup - Setup TDLS session
2172  * @message: Pointer to incoming dbus message
2173  * @wpa_s: wpa_supplicant structure for a network interface
2174  * Returns: NULL indicating success or DBus error message on failure
2175  *
2176  * Handler function for "TDLSSetup" method call of network interface.
2177  */
wpas_dbus_handler_tdls_setup(DBusMessage * message,struct wpa_supplicant * wpa_s)2178 DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
2179 					   struct wpa_supplicant *wpa_s)
2180 {
2181 	u8 peer[ETH_ALEN];
2182 	DBusMessage *error_reply;
2183 	int ret;
2184 
2185 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2186 		return error_reply;
2187 
2188 	wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
2189 
2190 	wpa_tdls_remove(wpa_s->wpa, peer);
2191 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2192 		ret = wpa_tdls_start(wpa_s->wpa, peer);
2193 	else
2194 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2195 
2196 	if (ret) {
2197 		return wpas_dbus_error_unknown_error(
2198 			message, "error performing TDLS setup");
2199 	}
2200 
2201 	return NULL;
2202 }
2203 
2204 
2205 /*
2206  * wpas_dbus_handler_tdls_status - Return TDLS session status
2207  * @message: Pointer to incoming dbus message
2208  * @wpa_s: wpa_supplicant structure for a network interface
2209  * Returns: A string representing the state of the link to this TDLS peer
2210  *
2211  * Handler function for "TDLSStatus" method call of network interface.
2212  */
wpas_dbus_handler_tdls_status(DBusMessage * message,struct wpa_supplicant * wpa_s)2213 DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
2214 					    struct wpa_supplicant *wpa_s)
2215 {
2216 	u8 peer[ETH_ALEN];
2217 	DBusMessage *reply;
2218 	const char *tdls_status;
2219 
2220 	if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
2221 		return reply;
2222 
2223 	wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
2224 
2225 	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
2226 
2227 	reply = dbus_message_new_method_return(message);
2228 	dbus_message_append_args(reply, DBUS_TYPE_STRING,
2229 				 &tdls_status, DBUS_TYPE_INVALID);
2230 	return reply;
2231 }
2232 
2233 
2234 /*
2235  * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
2236  * @message: Pointer to incoming dbus message
2237  * @wpa_s: wpa_supplicant structure for a network interface
2238  * Returns: NULL indicating success or DBus error message on failure
2239  *
2240  * Handler function for "TDLSTeardown" method call of network interface.
2241  */
wpas_dbus_handler_tdls_teardown(DBusMessage * message,struct wpa_supplicant * wpa_s)2242 DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
2243 					      struct wpa_supplicant *wpa_s)
2244 {
2245 	u8 peer[ETH_ALEN];
2246 	DBusMessage *error_reply;
2247 	int ret;
2248 
2249 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2250 		return error_reply;
2251 
2252 	wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
2253 
2254 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2255 		ret = wpa_tdls_teardown_link(
2256 			wpa_s->wpa, peer,
2257 			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
2258 	else
2259 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
2260 
2261 	if (ret) {
2262 		return wpas_dbus_error_unknown_error(
2263 			message, "error performing TDLS teardown");
2264 	}
2265 
2266 	return NULL;
2267 }
2268 
2269 #endif /* CONFIG_TDLS */
2270 
2271 
2272 /**
2273  * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
2274  * @message: Pointer to incoming dbus message
2275  * @wpa_s: %wpa_supplicant data structure
2276  * Returns: A dbus message containing an error on failure or NULL on success
2277  *
2278  * Sets the PKCS #11 engine and module path.
2279  */
wpas_dbus_handler_set_pkcs11_engine_and_module_path(DBusMessage * message,struct wpa_supplicant * wpa_s)2280 DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
2281 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2282 {
2283 	DBusMessageIter iter;
2284 	char *value = NULL;
2285 	char *pkcs11_engine_path = NULL;
2286 	char *pkcs11_module_path = NULL;
2287 
2288 	dbus_message_iter_init(message, &iter);
2289 	dbus_message_iter_get_basic(&iter, &value);
2290 	if (value == NULL) {
2291 		return dbus_message_new_error(
2292 			message, DBUS_ERROR_INVALID_ARGS,
2293 			"Invalid pkcs11_engine_path argument");
2294 	}
2295 	/* Empty path defaults to NULL */
2296 	if (os_strlen(value))
2297 		pkcs11_engine_path = value;
2298 
2299 	dbus_message_iter_next(&iter);
2300 	dbus_message_iter_get_basic(&iter, &value);
2301 	if (value == NULL) {
2302 		os_free(pkcs11_engine_path);
2303 		return dbus_message_new_error(
2304 			message, DBUS_ERROR_INVALID_ARGS,
2305 			"Invalid pkcs11_module_path argument");
2306 	}
2307 	/* Empty path defaults to NULL */
2308 	if (os_strlen(value))
2309 		pkcs11_module_path = value;
2310 
2311 	if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
2312 						   pkcs11_module_path))
2313 		return dbus_message_new_error(
2314 			message, DBUS_ERROR_FAILED,
2315 			"Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
2316 
2317 	if (wpa_s->dbus_new_path) {
2318 		wpa_dbus_mark_property_changed(
2319 			wpa_s->global->dbus, wpa_s->dbus_new_path,
2320 			WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
2321 		wpa_dbus_mark_property_changed(
2322 			wpa_s->global->dbus, wpa_s->dbus_new_path,
2323 			WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
2324 	}
2325 
2326 	return NULL;
2327 }
2328 
2329 
2330 /**
2331  * wpas_dbus_getter_capabilities - Return interface capabilities
2332  * @iter: Pointer to incoming dbus message iter
2333  * @error: Location to store error on failure
2334  * @user_data: Function specific data
2335  * Returns: TRUE on success, FALSE on failure
2336  *
2337  * Getter for "Capabilities" property of an interface.
2338  */
wpas_dbus_getter_capabilities(DBusMessageIter * iter,DBusError * error,void * user_data)2339 dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
2340 					  DBusError *error, void *user_data)
2341 {
2342 	struct wpa_supplicant *wpa_s = user_data;
2343 	struct wpa_driver_capa capa;
2344 	int res;
2345 	DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
2346 		variant_iter;
2347 	const char *scans[] = { "active", "passive", "ssid" };
2348 
2349 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
2350 					      "a{sv}", &variant_iter) ||
2351 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
2352 		goto nomem;
2353 
2354 	res = wpa_drv_get_capa(wpa_s, &capa);
2355 
2356 	/***** pairwise cipher */
2357 	if (res < 0) {
2358 		const char *args[] = {"ccmp", "tkip", "none"};
2359 
2360 		if (!wpa_dbus_dict_append_string_array(
2361 			    &iter_dict, "Pairwise", args,
2362 			    ARRAY_SIZE(args)))
2363 			goto nomem;
2364 	} else {
2365 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
2366 						      &iter_dict_entry,
2367 						      &iter_dict_val,
2368 						      &iter_array) ||
2369 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2370 		     !wpa_dbus_dict_string_array_add_element(
2371 			     &iter_array, "ccmp-256")) ||
2372 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2373 		     !wpa_dbus_dict_string_array_add_element(
2374 			     &iter_array, "gcmp-256")) ||
2375 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2376 		     !wpa_dbus_dict_string_array_add_element(
2377 			     &iter_array, "ccmp")) ||
2378 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2379 		     !wpa_dbus_dict_string_array_add_element(
2380 			     &iter_array, "gcmp")) ||
2381 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2382 		     !wpa_dbus_dict_string_array_add_element(
2383 			     &iter_array, "tkip")) ||
2384 		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2385 		     !wpa_dbus_dict_string_array_add_element(
2386 			     &iter_array, "none")) ||
2387 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2388 						    &iter_dict_entry,
2389 						    &iter_dict_val,
2390 						    &iter_array))
2391 			goto nomem;
2392 	}
2393 
2394 	/***** group cipher */
2395 	if (res < 0) {
2396 		const char *args[] = {
2397 			"ccmp", "tkip", "wep104", "wep40"
2398 		};
2399 
2400 		if (!wpa_dbus_dict_append_string_array(
2401 			    &iter_dict, "Group", args,
2402 			    ARRAY_SIZE(args)))
2403 			goto nomem;
2404 	} else {
2405 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
2406 						      &iter_dict_entry,
2407 						      &iter_dict_val,
2408 						      &iter_array) ||
2409 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2410 		     !wpa_dbus_dict_string_array_add_element(
2411 			     &iter_array, "ccmp-256")) ||
2412 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2413 		     !wpa_dbus_dict_string_array_add_element(
2414 			     &iter_array, "gcmp-256")) ||
2415 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2416 		     !wpa_dbus_dict_string_array_add_element(
2417 			     &iter_array, "ccmp")) ||
2418 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2419 		     !wpa_dbus_dict_string_array_add_element(
2420 			     &iter_array, "gcmp")) ||
2421 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2422 		     !wpa_dbus_dict_string_array_add_element(
2423 			     &iter_array, "tkip")) ||
2424 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
2425 		     !wpa_dbus_dict_string_array_add_element(
2426 			     &iter_array, "wep104")) ||
2427 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
2428 		     !wpa_dbus_dict_string_array_add_element(
2429 			     &iter_array, "wep40")) ||
2430 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2431 						    &iter_dict_entry,
2432 						    &iter_dict_val,
2433 						    &iter_array))
2434 			goto nomem;
2435 	}
2436 
2437 	/***** key management */
2438 	if (res < 0) {
2439 		const char *args[] = {
2440 			"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
2441 #ifdef CONFIG_WPS
2442 			"wps",
2443 #endif /* CONFIG_WPS */
2444 			"none"
2445 		};
2446 		if (!wpa_dbus_dict_append_string_array(
2447 			    &iter_dict, "KeyMgmt", args,
2448 			    ARRAY_SIZE(args)))
2449 			goto nomem;
2450 	} else {
2451 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
2452 						      &iter_dict_entry,
2453 						      &iter_dict_val,
2454 						      &iter_array) ||
2455 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
2456 							    "none") ||
2457 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
2458 							    "ieee8021x"))
2459 			goto nomem;
2460 
2461 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2462 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2463 			if (!wpa_dbus_dict_string_array_add_element(
2464 				    &iter_array, "wpa-eap") ||
2465 			    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
2466 			     !wpa_dbus_dict_string_array_add_element(
2467 				     &iter_array, "wpa-ft-eap")))
2468 				goto nomem;
2469 
2470 /* TODO: Ensure that driver actually supports sha256 encryption. */
2471 #ifdef CONFIG_IEEE80211W
2472 			if (!wpa_dbus_dict_string_array_add_element(
2473 				    &iter_array, "wpa-eap-sha256"))
2474 				goto nomem;
2475 #endif /* CONFIG_IEEE80211W */
2476 		}
2477 
2478 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2479 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2480 			if (!wpa_dbus_dict_string_array_add_element(
2481 				    &iter_array, "wpa-psk") ||
2482 			    ((capa.key_mgmt &
2483 			      WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
2484 			     !wpa_dbus_dict_string_array_add_element(
2485 				     &iter_array, "wpa-ft-psk")))
2486 				goto nomem;
2487 
2488 /* TODO: Ensure that driver actually supports sha256 encryption. */
2489 #ifdef CONFIG_IEEE80211W
2490 			if (!wpa_dbus_dict_string_array_add_element(
2491 				    &iter_array, "wpa-psk-sha256"))
2492 				goto nomem;
2493 #endif /* CONFIG_IEEE80211W */
2494 		}
2495 
2496 		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2497 		    !wpa_dbus_dict_string_array_add_element(&iter_array,
2498 							    "wpa-none"))
2499 			goto nomem;
2500 
2501 
2502 #ifdef CONFIG_WPS
2503 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2504 							    "wps"))
2505 			goto nomem;
2506 #endif /* CONFIG_WPS */
2507 
2508 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2509 						    &iter_dict_entry,
2510 						    &iter_dict_val,
2511 						    &iter_array))
2512 			goto nomem;
2513 	}
2514 
2515 	/***** WPA protocol */
2516 	if (res < 0) {
2517 		const char *args[] = { "rsn", "wpa" };
2518 
2519 		if (!wpa_dbus_dict_append_string_array(
2520 			    &iter_dict, "Protocol", args,
2521 			    ARRAY_SIZE(args)))
2522 			goto nomem;
2523 	} else {
2524 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
2525 						      &iter_dict_entry,
2526 						      &iter_dict_val,
2527 						      &iter_array) ||
2528 		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2529 				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
2530 		     !wpa_dbus_dict_string_array_add_element(
2531 			     &iter_array, "rsn")) ||
2532 		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2533 				       WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
2534 		     !wpa_dbus_dict_string_array_add_element(
2535 			     &iter_array, "wpa")) ||
2536 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2537 						    &iter_dict_entry,
2538 						    &iter_dict_val,
2539 						    &iter_array))
2540 			goto nomem;
2541 	}
2542 
2543 	/***** auth alg */
2544 	if (res < 0) {
2545 		const char *args[] = { "open", "shared", "leap" };
2546 
2547 		if (!wpa_dbus_dict_append_string_array(
2548 			    &iter_dict, "AuthAlg", args,
2549 			    ARRAY_SIZE(args)))
2550 			goto nomem;
2551 	} else {
2552 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
2553 						      &iter_dict_entry,
2554 						      &iter_dict_val,
2555 						      &iter_array))
2556 			goto nomem;
2557 
2558 		if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
2559 		     !wpa_dbus_dict_string_array_add_element(
2560 			     &iter_array, "open")) ||
2561 		    ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
2562 		     !wpa_dbus_dict_string_array_add_element(
2563 			     &iter_array, "shared")) ||
2564 		    ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
2565 		     !wpa_dbus_dict_string_array_add_element(
2566 			     &iter_array, "leap")) ||
2567 		    !wpa_dbus_dict_end_string_array(&iter_dict,
2568 						    &iter_dict_entry,
2569 						    &iter_dict_val,
2570 						    &iter_array))
2571 			goto nomem;
2572 	}
2573 
2574 	/***** Scan */
2575 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
2576 					       ARRAY_SIZE(scans)))
2577 		goto nomem;
2578 
2579 	/***** Modes */
2580 	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
2581 					      &iter_dict_entry,
2582 					      &iter_dict_val,
2583 					      &iter_array) ||
2584 	    !wpa_dbus_dict_string_array_add_element(
2585 		    &iter_array, "infrastructure") ||
2586 	    !wpa_dbus_dict_string_array_add_element(
2587 		    &iter_array, "ad-hoc") ||
2588 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
2589 	     !wpa_dbus_dict_string_array_add_element(
2590 		     &iter_array, "ap")) ||
2591 	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
2592 	     !wpa_dbus_dict_string_array_add_element(
2593 		     &iter_array, "p2p")) ||
2594 	    !wpa_dbus_dict_end_string_array(&iter_dict,
2595 					    &iter_dict_entry,
2596 					    &iter_dict_val,
2597 					    &iter_array))
2598 		goto nomem;
2599 	/***** Modes end */
2600 
2601 	if (res >= 0) {
2602 		dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
2603 
2604 		if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
2605 						max_scan_ssid))
2606 			goto nomem;
2607 	}
2608 
2609 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
2610 	    !dbus_message_iter_close_container(iter, &variant_iter))
2611 		goto nomem;
2612 
2613 	return TRUE;
2614 
2615 nomem:
2616 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2617 	return FALSE;
2618 }
2619 
2620 
2621 /**
2622  * wpas_dbus_getter_state - Get interface state
2623  * @iter: Pointer to incoming dbus message iter
2624  * @error: Location to store error on failure
2625  * @user_data: Function specific data
2626  * Returns: TRUE on success, FALSE on failure
2627  *
2628  * Getter for "State" property.
2629  */
wpas_dbus_getter_state(DBusMessageIter * iter,DBusError * error,void * user_data)2630 dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
2631 				   void *user_data)
2632 {
2633 	struct wpa_supplicant *wpa_s = user_data;
2634 	const char *str_state;
2635 	char *state_ls, *tmp;
2636 	dbus_bool_t success = FALSE;
2637 
2638 	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
2639 
2640 	/* make state string lowercase to fit new DBus API convention
2641 	 */
2642 	state_ls = tmp = os_strdup(str_state);
2643 	if (!tmp) {
2644 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2645 		return FALSE;
2646 	}
2647 	while (*tmp) {
2648 		*tmp = tolower(*tmp);
2649 		tmp++;
2650 	}
2651 
2652 	success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2653 						   &state_ls, error);
2654 
2655 	os_free(state_ls);
2656 
2657 	return success;
2658 }
2659 
2660 
2661 /**
2662  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
2663  * @iter: Pointer to incoming dbus message iter
2664  * @error: Location to store error on failure
2665  * @user_data: Function specific data
2666  * Returns: TRUE on success, FALSE on failure
2667  *
2668  * Getter for "scanning" property.
2669  */
wpas_dbus_getter_scanning(DBusMessageIter * iter,DBusError * error,void * user_data)2670 dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
2671 				      void *user_data)
2672 {
2673 	struct wpa_supplicant *wpa_s = user_data;
2674 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
2675 
2676 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2677 						&scanning, error);
2678 }
2679 
2680 
2681 /**
2682  * wpas_dbus_getter_ap_scan - Control roaming mode
2683  * @iter: Pointer to incoming dbus message iter
2684  * @error: Location to store error on failure
2685  * @user_data: Function specific data
2686  * Returns: TRUE on success, FALSE on failure
2687  *
2688  * Getter function for "ApScan" property.
2689  */
wpas_dbus_getter_ap_scan(DBusMessageIter * iter,DBusError * error,void * user_data)2690 dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
2691 				     void *user_data)
2692 {
2693 	struct wpa_supplicant *wpa_s = user_data;
2694 	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
2695 
2696 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2697 						&ap_scan, error);
2698 }
2699 
2700 
2701 /**
2702  * wpas_dbus_setter_ap_scan - Control roaming mode
2703  * @iter: Pointer to incoming dbus message iter
2704  * @error: Location to store error on failure
2705  * @user_data: Function specific data
2706  * Returns: TRUE on success, FALSE on failure
2707  *
2708  * Setter function for "ApScan" property.
2709  */
wpas_dbus_setter_ap_scan(DBusMessageIter * iter,DBusError * error,void * user_data)2710 dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
2711 				     void *user_data)
2712 {
2713 	struct wpa_supplicant *wpa_s = user_data;
2714 	dbus_uint32_t ap_scan;
2715 
2716 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2717 					      &ap_scan))
2718 		return FALSE;
2719 
2720 	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
2721 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2722 				     "ap_scan must be 0, 1, or 2");
2723 		return FALSE;
2724 	}
2725 	return TRUE;
2726 }
2727 
2728 
2729 /**
2730  * wpas_dbus_getter_fast_reauth - Control fast
2731  * reauthentication (TLS session resumption)
2732  * @iter: Pointer to incoming dbus message iter
2733  * @error: Location to store error on failure
2734  * @user_data: Function specific data
2735  * Returns: TRUE on success, FALSE on failure
2736  *
2737  * Getter function for "FastReauth" property.
2738  */
wpas_dbus_getter_fast_reauth(DBusMessageIter * iter,DBusError * error,void * user_data)2739 dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
2740 					 DBusError *error,
2741 					 void *user_data)
2742 {
2743 	struct wpa_supplicant *wpa_s = user_data;
2744 	dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
2745 
2746 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2747 						&fast_reauth, error);
2748 }
2749 
2750 
2751 /**
2752  * wpas_dbus_setter_fast_reauth - Control fast
2753  * reauthentication (TLS session resumption)
2754  * @iter: Pointer to incoming dbus message iter
2755  * @error: Location to store error on failure
2756  * @user_data: Function specific data
2757  * Returns: TRUE on success, FALSE on failure
2758  *
2759  * Setter function for "FastReauth" property.
2760  */
wpas_dbus_setter_fast_reauth(DBusMessageIter * iter,DBusError * error,void * user_data)2761 dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
2762 				     DBusError *error,
2763 				     void *user_data)
2764 {
2765 	struct wpa_supplicant *wpa_s = user_data;
2766 	dbus_bool_t fast_reauth;
2767 
2768 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
2769 					      &fast_reauth))
2770 		return FALSE;
2771 
2772 	wpa_s->conf->fast_reauth = fast_reauth;
2773 	return TRUE;
2774 }
2775 
2776 
2777 /**
2778  * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
2779  * @iter: Pointer to incoming dbus message iter
2780  * @error: Location to store error on failure
2781  * @user_data: Function specific data
2782  * Returns: TRUE on success, FALSE on failure
2783  *
2784  * Getter for "DisconnectReason" property.  The reason is negative if it is
2785  * locally generated.
2786  */
wpas_dbus_getter_disconnect_reason(DBusMessageIter * iter,DBusError * error,void * user_data)2787 dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
2788 					       DBusError *error,
2789 					       void *user_data)
2790 {
2791 	struct wpa_supplicant *wpa_s = user_data;
2792 	dbus_int32_t reason = wpa_s->disconnect_reason;
2793 
2794 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
2795 						&reason, error);
2796 }
2797 
2798 
2799 /**
2800  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
2801  * @iter: Pointer to incoming dbus message iter
2802  * @error: Location to store error on failure
2803  * @user_data: Function specific data
2804  * Returns: TRUE on success, FALSE on failure
2805  *
2806  * Getter function for "BSSExpireAge" property.
2807  */
wpas_dbus_getter_bss_expire_age(DBusMessageIter * iter,DBusError * error,void * user_data)2808 dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
2809 					    DBusError *error,
2810 					    void *user_data)
2811 {
2812 	struct wpa_supplicant *wpa_s = user_data;
2813 	dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
2814 
2815 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2816 						&expire_age, error);
2817 }
2818 
2819 
2820 /**
2821  * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
2822  * @iter: Pointer to incoming dbus message iter
2823  * @error: Location to store error on failure
2824  * @user_data: Function specific data
2825  * Returns: TRUE on success, FALSE on failure
2826  *
2827  * Setter function for "BSSExpireAge" property.
2828  */
wpas_dbus_setter_bss_expire_age(DBusMessageIter * iter,DBusError * error,void * user_data)2829 dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
2830 					    DBusError *error,
2831 					    void *user_data)
2832 {
2833 	struct wpa_supplicant *wpa_s = user_data;
2834 	dbus_uint32_t expire_age;
2835 
2836 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2837 					      &expire_age))
2838 		return FALSE;
2839 
2840 	if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
2841 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2842 				     "BSSExpireAge must be >= 10");
2843 		return FALSE;
2844 	}
2845 	return TRUE;
2846 }
2847 
2848 
2849 /**
2850  * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
2851  * @iter: Pointer to incoming dbus message iter
2852  * @error: Location to store error on failure
2853  * @user_data: Function specific data
2854  * Returns: TRUE on success, FALSE on failure
2855  *
2856  * Getter function for "BSSExpireCount" property.
2857  */
wpas_dbus_getter_bss_expire_count(DBusMessageIter * iter,DBusError * error,void * user_data)2858 dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
2859 					      DBusError *error,
2860 					      void *user_data)
2861 {
2862 	struct wpa_supplicant *wpa_s = user_data;
2863 	dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
2864 
2865 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2866 						&expire_count, error);
2867 }
2868 
2869 
2870 /**
2871  * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
2872  * @iter: Pointer to incoming dbus message iter
2873  * @error: Location to store error on failure
2874  * @user_data: Function specific data
2875  * Returns: TRUE on success, FALSE on failure
2876  *
2877  * Setter function for "BSSExpireCount" property.
2878  */
wpas_dbus_setter_bss_expire_count(DBusMessageIter * iter,DBusError * error,void * user_data)2879 dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
2880 					      DBusError *error,
2881 					      void *user_data)
2882 {
2883 	struct wpa_supplicant *wpa_s = user_data;
2884 	dbus_uint32_t expire_count;
2885 
2886 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2887 					      &expire_count))
2888 		return FALSE;
2889 
2890 	if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
2891 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2892 				     "BSSExpireCount must be > 0");
2893 		return FALSE;
2894 	}
2895 	return TRUE;
2896 }
2897 
2898 
2899 /**
2900  * wpas_dbus_getter_country - Control country code
2901  * @iter: Pointer to incoming dbus message iter
2902  * @error: Location to store error on failure
2903  * @user_data: Function specific data
2904  * Returns: TRUE on success, FALSE on failure
2905  *
2906  * Getter function for "Country" property.
2907  */
wpas_dbus_getter_country(DBusMessageIter * iter,DBusError * error,void * user_data)2908 dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
2909 				     void *user_data)
2910 {
2911 	struct wpa_supplicant *wpa_s = user_data;
2912 	char country[3];
2913 	char *str = country;
2914 
2915 	country[0] = wpa_s->conf->country[0];
2916 	country[1] = wpa_s->conf->country[1];
2917 	country[2] = '\0';
2918 
2919 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2920 						&str, error);
2921 }
2922 
2923 
2924 /**
2925  * wpas_dbus_setter_country - Control country code
2926  * @iter: Pointer to incoming dbus message iter
2927  * @error: Location to store error on failure
2928  * @user_data: Function specific data
2929  * Returns: TRUE on success, FALSE on failure
2930  *
2931  * Setter function for "Country" property.
2932  */
wpas_dbus_setter_country(DBusMessageIter * iter,DBusError * error,void * user_data)2933 dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
2934 				     void *user_data)
2935 {
2936 	struct wpa_supplicant *wpa_s = user_data;
2937 	const char *country;
2938 
2939 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
2940 					      &country))
2941 		return FALSE;
2942 
2943 	if (!country[0] || !country[1]) {
2944 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2945 				     "invalid country code");
2946 		return FALSE;
2947 	}
2948 
2949 	if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
2950 		wpa_printf(MSG_DEBUG, "Failed to set country");
2951 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2952 				     "failed to set country code");
2953 		return FALSE;
2954 	}
2955 
2956 	wpa_s->conf->country[0] = country[0];
2957 	wpa_s->conf->country[1] = country[1];
2958 	return TRUE;
2959 }
2960 
2961 
2962 /**
2963  * wpas_dbus_getter_scan_interval - Get scan interval
2964  * @iter: Pointer to incoming dbus message iter
2965  * @error: Location to store error on failure
2966  * @user_data: Function specific data
2967  * Returns: TRUE on success, FALSE on failure
2968  *
2969  * Getter function for "ScanInterval" property.
2970  */
wpas_dbus_getter_scan_interval(DBusMessageIter * iter,DBusError * error,void * user_data)2971 dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
2972 					   DBusError *error,
2973 					   void *user_data)
2974 {
2975 	struct wpa_supplicant *wpa_s = user_data;
2976 	dbus_int32_t scan_interval = wpa_s->scan_interval;
2977 
2978 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
2979 						&scan_interval, error);
2980 }
2981 
2982 
2983 /**
2984  * wpas_dbus_setter_scan_interval - Control scan interval
2985  * @iter: Pointer to incoming dbus message iter
2986  * @error: Location to store error on failure
2987  * @user_data: Function specific data
2988  * Returns: TRUE on success, FALSE on failure
2989  *
2990  * Setter function for "ScanInterval" property.
2991  */
wpas_dbus_setter_scan_interval(DBusMessageIter * iter,DBusError * error,void * user_data)2992 dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
2993 					   DBusError *error,
2994 					   void *user_data)
2995 {
2996 	struct wpa_supplicant *wpa_s = user_data;
2997 	dbus_int32_t scan_interval;
2998 
2999 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
3000 					      &scan_interval))
3001 		return FALSE;
3002 
3003 	if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
3004 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3005 				     "scan_interval must be >= 0");
3006 		return FALSE;
3007 	}
3008 	return TRUE;
3009 }
3010 
3011 
3012 /**
3013  * wpas_dbus_getter_ifname - Get interface name
3014  * @iter: Pointer to incoming dbus message iter
3015  * @error: Location to store error on failure
3016  * @user_data: Function specific data
3017  * Returns: TRUE on success, FALSE on failure
3018  *
3019  * Getter for "Ifname" property.
3020  */
wpas_dbus_getter_ifname(DBusMessageIter * iter,DBusError * error,void * user_data)3021 dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
3022 				    void *user_data)
3023 {
3024 	struct wpa_supplicant *wpa_s = user_data;
3025 	const char *ifname = wpa_s->ifname;
3026 
3027 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3028 						&ifname, error);
3029 }
3030 
3031 
3032 /**
3033  * wpas_dbus_getter_driver - Get interface name
3034  * @iter: Pointer to incoming dbus message iter
3035  * @error: Location to store error on failure
3036  * @user_data: Function specific data
3037  * Returns: TRUE on success, FALSE on failure
3038  *
3039  * Getter for "Driver" property.
3040  */
wpas_dbus_getter_driver(DBusMessageIter * iter,DBusError * error,void * user_data)3041 dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
3042 				    void *user_data)
3043 {
3044 	struct wpa_supplicant *wpa_s = user_data;
3045 	const char *driver;
3046 
3047 	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
3048 		wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
3049 			   __func__);
3050 		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
3051 			       __func__);
3052 		return FALSE;
3053 	}
3054 
3055 	driver = wpa_s->driver->name;
3056 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3057 						&driver, error);
3058 }
3059 
3060 
3061 /**
3062  * wpas_dbus_getter_current_bss - Get current bss object path
3063  * @iter: Pointer to incoming dbus message iter
3064  * @error: Location to store error on failure
3065  * @user_data: Function specific data
3066  * Returns: TRUE on success, FALSE on failure
3067  *
3068  * Getter for "CurrentBSS" property.
3069  */
wpas_dbus_getter_current_bss(DBusMessageIter * iter,DBusError * error,void * user_data)3070 dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
3071 					 DBusError *error,
3072 					 void *user_data)
3073 {
3074 	struct wpa_supplicant *wpa_s = user_data;
3075 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
3076 
3077 	if (wpa_s->current_bss && wpa_s->dbus_new_path)
3078 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3079 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3080 			    wpa_s->dbus_new_path, wpa_s->current_bss->id);
3081 	else
3082 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3083 
3084 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3085 						&bss_obj_path, error);
3086 }
3087 
3088 
3089 /**
3090  * wpas_dbus_getter_current_network - Get current network object path
3091  * @iter: Pointer to incoming dbus message iter
3092  * @error: Location to store error on failure
3093  * @user_data: Function specific data
3094  * Returns: TRUE on success, FALSE on failure
3095  *
3096  * Getter for "CurrentNetwork" property.
3097  */
wpas_dbus_getter_current_network(DBusMessageIter * iter,DBusError * error,void * user_data)3098 dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
3099 					     DBusError *error,
3100 					     void *user_data)
3101 {
3102 	struct wpa_supplicant *wpa_s = user_data;
3103 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
3104 
3105 	if (wpa_s->current_ssid && wpa_s->dbus_new_path)
3106 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3107 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
3108 			    wpa_s->dbus_new_path, wpa_s->current_ssid->id);
3109 	else
3110 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3111 
3112 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3113 						&net_obj_path, error);
3114 }
3115 
3116 
3117 /**
3118  * wpas_dbus_getter_current_auth_mode - Get current authentication type
3119  * @iter: Pointer to incoming dbus message iter
3120  * @error: Location to store error on failure
3121  * @user_data: Function specific data
3122  * Returns: TRUE on success, FALSE on failure
3123  *
3124  * Getter for "CurrentAuthMode" property.
3125  */
wpas_dbus_getter_current_auth_mode(DBusMessageIter * iter,DBusError * error,void * user_data)3126 dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
3127 					       DBusError *error,
3128 					       void *user_data)
3129 {
3130 	struct wpa_supplicant *wpa_s = user_data;
3131 	const char *eap_mode;
3132 	const char *auth_mode;
3133 	char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
3134 
3135 	if (wpa_s->wpa_state != WPA_COMPLETED) {
3136 		auth_mode = "INACTIVE";
3137 	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
3138 	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3139 		eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
3140 		os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
3141 			    "EAP-%s", eap_mode);
3142 		auth_mode = eap_mode_buf;
3143 
3144 	} else {
3145 		auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
3146 					     wpa_s->current_ssid->proto);
3147 	}
3148 
3149 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3150 						&auth_mode, error);
3151 }
3152 
3153 
3154 /**
3155  * wpas_dbus_getter_bridge_ifname - Get interface name
3156  * @iter: Pointer to incoming dbus message iter
3157  * @error: Location to store error on failure
3158  * @user_data: Function specific data
3159  * Returns: TRUE on success, FALSE on failure
3160  *
3161  * Getter for "BridgeIfname" property.
3162  */
wpas_dbus_getter_bridge_ifname(DBusMessageIter * iter,DBusError * error,void * user_data)3163 dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
3164 					   DBusError *error,
3165 					   void *user_data)
3166 {
3167 	struct wpa_supplicant *wpa_s = user_data;
3168 	const char *bridge_ifname = wpa_s->bridge_ifname;
3169 
3170 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3171 						&bridge_ifname, error);
3172 }
3173 
3174 
3175 /**
3176  * wpas_dbus_getter_bsss - Get array of BSSs objects
3177  * @iter: Pointer to incoming dbus message iter
3178  * @error: Location to store error on failure
3179  * @user_data: Function specific data
3180  * Returns: TRUE on success, FALSE on failure
3181  *
3182  * Getter for "BSSs" property.
3183  */
wpas_dbus_getter_bsss(DBusMessageIter * iter,DBusError * error,void * user_data)3184 dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
3185 				  void *user_data)
3186 {
3187 	struct wpa_supplicant *wpa_s = user_data;
3188 	struct wpa_bss *bss;
3189 	char **paths;
3190 	unsigned int i = 0;
3191 	dbus_bool_t success = FALSE;
3192 
3193 	if (!wpa_s->dbus_new_path) {
3194 		dbus_set_error(error, DBUS_ERROR_FAILED,
3195 			       "%s: no D-Bus interface", __func__);
3196 		return FALSE;
3197 	}
3198 
3199 	paths = os_calloc(wpa_s->num_bss, sizeof(char *));
3200 	if (!paths) {
3201 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3202 		return FALSE;
3203 	}
3204 
3205 	/* Loop through scan results and append each result's object path */
3206 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
3207 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3208 		if (paths[i] == NULL) {
3209 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3210 					     "no memory");
3211 			goto out;
3212 		}
3213 		/* Construct the object path for this BSS. */
3214 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3215 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3216 			    wpa_s->dbus_new_path, bss->id);
3217 	}
3218 
3219 	success = wpas_dbus_simple_array_property_getter(iter,
3220 							 DBUS_TYPE_OBJECT_PATH,
3221 							 paths, wpa_s->num_bss,
3222 							 error);
3223 
3224 out:
3225 	while (i)
3226 		os_free(paths[--i]);
3227 	os_free(paths);
3228 	return success;
3229 }
3230 
3231 
3232 /**
3233  * wpas_dbus_getter_networks - Get array of networks objects
3234  * @iter: Pointer to incoming dbus message iter
3235  * @error: Location to store error on failure
3236  * @user_data: Function specific data
3237  * Returns: TRUE on success, FALSE on failure
3238  *
3239  * Getter for "Networks" property.
3240  */
wpas_dbus_getter_networks(DBusMessageIter * iter,DBusError * error,void * user_data)3241 dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
3242 				      void *user_data)
3243 {
3244 	struct wpa_supplicant *wpa_s = user_data;
3245 	struct wpa_ssid *ssid;
3246 	char **paths;
3247 	unsigned int i = 0, num = 0;
3248 	dbus_bool_t success = FALSE;
3249 
3250 	if (!wpa_s->dbus_new_path) {
3251 		dbus_set_error(error, DBUS_ERROR_FAILED,
3252 			       "%s: no D-Bus interface", __func__);
3253 		return FALSE;
3254 	}
3255 
3256 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
3257 		if (!network_is_persistent_group(ssid))
3258 			num++;
3259 
3260 	paths = os_calloc(num, sizeof(char *));
3261 	if (!paths) {
3262 		dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3263 		return FALSE;
3264 	}
3265 
3266 	/* Loop through configured networks and append object path of each */
3267 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
3268 		if (network_is_persistent_group(ssid))
3269 			continue;
3270 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3271 		if (paths[i] == NULL) {
3272 			dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
3273 				       "no memory");
3274 			goto out;
3275 		}
3276 
3277 		/* Construct the object path for this network. */
3278 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3279 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
3280 			    wpa_s->dbus_new_path, ssid->id);
3281 	}
3282 
3283 	success = wpas_dbus_simple_array_property_getter(iter,
3284 							 DBUS_TYPE_OBJECT_PATH,
3285 							 paths, num, error);
3286 
3287 out:
3288 	while (i)
3289 		os_free(paths[--i]);
3290 	os_free(paths);
3291 	return success;
3292 }
3293 
3294 
3295 /**
3296  * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
3297  * @iter: Pointer to incoming dbus message iter
3298  * @error: Location to store error on failure
3299  * @user_data: Function specific data
3300  * Returns: A dbus message containing the PKCS #11 engine path
3301  *
3302  * Getter for "PKCS11EnginePath" property.
3303  */
wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter * iter,DBusError * error,void * user_data)3304 dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
3305 						DBusError *error,
3306 						void *user_data)
3307 {
3308 	struct wpa_supplicant *wpa_s = user_data;
3309 	const char *pkcs11_engine_path;
3310 
3311 	if (wpa_s->conf->pkcs11_engine_path == NULL)
3312 		pkcs11_engine_path = "";
3313 	else
3314 		pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
3315 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3316 						&pkcs11_engine_path, error);
3317 }
3318 
3319 
3320 /**
3321  * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
3322  * @iter: Pointer to incoming dbus message iter
3323  * @error: Location to store error on failure
3324  * @user_data: Function specific data
3325  * Returns: A dbus message containing the PKCS #11 module path
3326  *
3327  * Getter for "PKCS11ModulePath" property.
3328  */
wpas_dbus_getter_pkcs11_module_path(DBusMessageIter * iter,DBusError * error,void * user_data)3329 dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
3330 						DBusError *error,
3331 						void *user_data)
3332 {
3333 	struct wpa_supplicant *wpa_s = user_data;
3334 	const char *pkcs11_module_path;
3335 
3336 	if (wpa_s->conf->pkcs11_module_path == NULL)
3337 		pkcs11_module_path = "";
3338 	else
3339 		pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
3340 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3341 						&pkcs11_module_path, error);
3342 }
3343 
3344 
3345 /**
3346  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
3347  * @iter: Pointer to incoming dbus message iter
3348  * @error: Location to store error on failure
3349  * @user_data: Function specific data
3350  * Returns: TRUE on success, FALSE on failure
3351  *
3352  * Getter for "Blobs" property.
3353  */
wpas_dbus_getter_blobs(DBusMessageIter * iter,DBusError * error,void * user_data)3354 dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
3355 				   void *user_data)
3356 {
3357 	struct wpa_supplicant *wpa_s = user_data;
3358 	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
3359 	struct wpa_config_blob *blob;
3360 
3361 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3362 					      "a{say}", &variant_iter) ||
3363 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
3364 					      "{say}", &dict_iter)) {
3365 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3366 		return FALSE;
3367 	}
3368 
3369 	blob = wpa_s->conf->blobs;
3370 	while (blob) {
3371 		if (!dbus_message_iter_open_container(&dict_iter,
3372 						      DBUS_TYPE_DICT_ENTRY,
3373 						      NULL, &entry_iter) ||
3374 		    !dbus_message_iter_append_basic(&entry_iter,
3375 						    DBUS_TYPE_STRING,
3376 						    &(blob->name)) ||
3377 		    !dbus_message_iter_open_container(&entry_iter,
3378 						      DBUS_TYPE_ARRAY,
3379 						      DBUS_TYPE_BYTE_AS_STRING,
3380 						      &array_iter) ||
3381 		    !dbus_message_iter_append_fixed_array(&array_iter,
3382 							  DBUS_TYPE_BYTE,
3383 							  &(blob->data),
3384 							  blob->len) ||
3385 		    !dbus_message_iter_close_container(&entry_iter,
3386 						       &array_iter) ||
3387 		    !dbus_message_iter_close_container(&dict_iter,
3388 						       &entry_iter)) {
3389 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3390 					     "no memory");
3391 			return FALSE;
3392 		}
3393 
3394 		blob = blob->next;
3395 	}
3396 
3397 	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
3398 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
3399 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3400 		return FALSE;
3401 	}
3402 
3403 	return TRUE;
3404 }
3405 
3406 
get_bss_helper(struct bss_handler_args * args,DBusError * error,const char * func_name)3407 static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
3408 				       DBusError *error, const char *func_name)
3409 {
3410 	struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
3411 
3412 	if (!res) {
3413 		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
3414 			   func_name, args->id);
3415 		dbus_set_error(error, DBUS_ERROR_FAILED,
3416 			       "%s: BSS %d not found",
3417 			       func_name, args->id);
3418 	}
3419 
3420 	return res;
3421 }
3422 
3423 
3424 /**
3425  * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
3426  * @iter: Pointer to incoming dbus message iter
3427  * @error: Location to store error on failure
3428  * @user_data: Function specific data
3429  * Returns: TRUE on success, FALSE on failure
3430  *
3431  * Getter for "BSSID" property.
3432  */
wpas_dbus_getter_bss_bssid(DBusMessageIter * iter,DBusError * error,void * user_data)3433 dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
3434 				       void *user_data)
3435 {
3436 	struct bss_handler_args *args = user_data;
3437 	struct wpa_bss *res;
3438 
3439 	res = get_bss_helper(args, error, __func__);
3440 	if (!res)
3441 		return FALSE;
3442 
3443 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3444 						      res->bssid, ETH_ALEN,
3445 						      error);
3446 }
3447 
3448 
3449 /**
3450  * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
3451  * @iter: Pointer to incoming dbus message iter
3452  * @error: Location to store error on failure
3453  * @user_data: Function specific data
3454  * Returns: TRUE on success, FALSE on failure
3455  *
3456  * Getter for "SSID" property.
3457  */
wpas_dbus_getter_bss_ssid(DBusMessageIter * iter,DBusError * error,void * user_data)3458 dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
3459 				      void *user_data)
3460 {
3461 	struct bss_handler_args *args = user_data;
3462 	struct wpa_bss *res;
3463 
3464 	res = get_bss_helper(args, error, __func__);
3465 	if (!res)
3466 		return FALSE;
3467 
3468 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3469 						      res->ssid, res->ssid_len,
3470 						      error);
3471 }
3472 
3473 
3474 /**
3475  * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
3476  * @iter: Pointer to incoming dbus message iter
3477  * @error: Location to store error on failure
3478  * @user_data: Function specific data
3479  * Returns: TRUE on success, FALSE on failure
3480  *
3481  * Getter for "Privacy" property.
3482  */
wpas_dbus_getter_bss_privacy(DBusMessageIter * iter,DBusError * error,void * user_data)3483 dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
3484 					 DBusError *error, void *user_data)
3485 {
3486 	struct bss_handler_args *args = user_data;
3487 	struct wpa_bss *res;
3488 	dbus_bool_t privacy;
3489 
3490 	res = get_bss_helper(args, error, __func__);
3491 	if (!res)
3492 		return FALSE;
3493 
3494 	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
3495 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3496 						&privacy, error);
3497 }
3498 
3499 
3500 /**
3501  * wpas_dbus_getter_bss_mode - Return the mode of a BSS
3502  * @iter: Pointer to incoming dbus message iter
3503  * @error: Location to store error on failure
3504  * @user_data: Function specific data
3505  * Returns: TRUE on success, FALSE on failure
3506  *
3507  * Getter for "Mode" property.
3508  */
wpas_dbus_getter_bss_mode(DBusMessageIter * iter,DBusError * error,void * user_data)3509 dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
3510 				      void *user_data)
3511 {
3512 	struct bss_handler_args *args = user_data;
3513 	struct wpa_bss *res;
3514 	const char *mode;
3515 
3516 	res = get_bss_helper(args, error, __func__);
3517 	if (!res)
3518 		return FALSE;
3519 	if (bss_is_dmg(res)) {
3520 		switch (res->caps & IEEE80211_CAP_DMG_MASK) {
3521 		case IEEE80211_CAP_DMG_PBSS:
3522 		case IEEE80211_CAP_DMG_IBSS:
3523 			mode = "ad-hoc";
3524 			break;
3525 		case IEEE80211_CAP_DMG_AP:
3526 			mode = "infrastructure";
3527 			break;
3528 		}
3529 	} else {
3530 		if (res->caps & IEEE80211_CAP_IBSS)
3531 			mode = "ad-hoc";
3532 		else
3533 			mode = "infrastructure";
3534 	}
3535 
3536 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3537 						&mode, error);
3538 }
3539 
3540 
3541 /**
3542  * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
3543  * @iter: Pointer to incoming dbus message iter
3544  * @error: Location to store error on failure
3545  * @user_data: Function specific data
3546  * Returns: TRUE on success, FALSE on failure
3547  *
3548  * Getter for "Level" property.
3549  */
wpas_dbus_getter_bss_signal(DBusMessageIter * iter,DBusError * error,void * user_data)3550 dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
3551 					DBusError *error, void *user_data)
3552 {
3553 	struct bss_handler_args *args = user_data;
3554 	struct wpa_bss *res;
3555 	s16 level;
3556 
3557 	res = get_bss_helper(args, error, __func__);
3558 	if (!res)
3559 		return FALSE;
3560 
3561 	level = (s16) res->level;
3562 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
3563 						&level, error);
3564 }
3565 
3566 
3567 /**
3568  * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
3569  * @iter: Pointer to incoming dbus message iter
3570  * @error: Location to store error on failure
3571  * @user_data: Function specific data
3572  * Returns: TRUE on success, FALSE on failure
3573  *
3574  * Getter for "Frequency" property.
3575  */
wpas_dbus_getter_bss_frequency(DBusMessageIter * iter,DBusError * error,void * user_data)3576 dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
3577 					   DBusError *error, void *user_data)
3578 {
3579 	struct bss_handler_args *args = user_data;
3580 	struct wpa_bss *res;
3581 	u16 freq;
3582 
3583 	res = get_bss_helper(args, error, __func__);
3584 	if (!res)
3585 		return FALSE;
3586 
3587 	freq = (u16) res->freq;
3588 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
3589 						&freq, error);
3590 }
3591 
3592 
cmp_u8s_desc(const void * a,const void * b)3593 static int cmp_u8s_desc(const void *a, const void *b)
3594 {
3595 	return (*(u8 *) b - *(u8 *) a);
3596 }
3597 
3598 
3599 /**
3600  * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
3601  * @iter: Pointer to incoming dbus message iter
3602  * @error: Location to store error on failure
3603  * @user_data: Function specific data
3604  * Returns: TRUE on success, FALSE on failure
3605  *
3606  * Getter for "Rates" property.
3607  */
wpas_dbus_getter_bss_rates(DBusMessageIter * iter,DBusError * error,void * user_data)3608 dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
3609 				       DBusError *error, void *user_data)
3610 {
3611 	struct bss_handler_args *args = user_data;
3612 	struct wpa_bss *res;
3613 	u8 *ie_rates = NULL;
3614 	u32 *real_rates;
3615 	int rates_num, i;
3616 	dbus_bool_t success = FALSE;
3617 
3618 	res = get_bss_helper(args, error, __func__);
3619 	if (!res)
3620 		return FALSE;
3621 
3622 	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
3623 	if (rates_num < 0)
3624 		return FALSE;
3625 
3626 	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
3627 
3628 	real_rates = os_malloc(sizeof(u32) * rates_num);
3629 	if (!real_rates) {
3630 		os_free(ie_rates);
3631 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3632 		return FALSE;
3633 	}
3634 
3635 	for (i = 0; i < rates_num; i++)
3636 		real_rates[i] = ie_rates[i] * 500000;
3637 
3638 	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
3639 							 real_rates, rates_num,
3640 							 error);
3641 
3642 	os_free(ie_rates);
3643 	os_free(real_rates);
3644 	return success;
3645 }
3646 
3647 
wpas_dbus_get_bss_security_prop(DBusMessageIter * iter,struct wpa_ie_data * ie_data,DBusError * error)3648 static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
3649 						   struct wpa_ie_data *ie_data,
3650 						   DBusError *error)
3651 {
3652 	DBusMessageIter iter_dict, variant_iter;
3653 	const char *group;
3654 	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
3655 	const char *key_mgmt[9]; /* max 9 key managements may be supported */
3656 	int n;
3657 
3658 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3659 					      "a{sv}", &variant_iter))
3660 		goto nomem;
3661 
3662 	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3663 		goto nomem;
3664 
3665 	/* KeyMgmt */
3666 	n = 0;
3667 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
3668 		key_mgmt[n++] = "wpa-psk";
3669 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
3670 		key_mgmt[n++] = "wpa-ft-psk";
3671 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
3672 		key_mgmt[n++] = "wpa-psk-sha256";
3673 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
3674 		key_mgmt[n++] = "wpa-eap";
3675 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
3676 		key_mgmt[n++] = "wpa-ft-eap";
3677 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
3678 		key_mgmt[n++] = "wpa-eap-sha256";
3679 #ifdef CONFIG_SUITEB
3680 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
3681 		key_mgmt[n++] = "wpa-eap-suite-b";
3682 #endif /* CONFIG_SUITEB */
3683 #ifdef CONFIG_SUITEB192
3684 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
3685 		key_mgmt[n++] = "wpa-eap-suite-b-192";
3686 #endif /* CONFIG_SUITEB192 */
3687 	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
3688 		key_mgmt[n++] = "wpa-none";
3689 
3690 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
3691 					       key_mgmt, n))
3692 		goto nomem;
3693 
3694 	/* Group */
3695 	switch (ie_data->group_cipher) {
3696 	case WPA_CIPHER_WEP40:
3697 		group = "wep40";
3698 		break;
3699 	case WPA_CIPHER_TKIP:
3700 		group = "tkip";
3701 		break;
3702 	case WPA_CIPHER_CCMP:
3703 		group = "ccmp";
3704 		break;
3705 	case WPA_CIPHER_GCMP:
3706 		group = "gcmp";
3707 		break;
3708 	case WPA_CIPHER_WEP104:
3709 		group = "wep104";
3710 		break;
3711 	case WPA_CIPHER_CCMP_256:
3712 		group = "ccmp-256";
3713 		break;
3714 	case WPA_CIPHER_GCMP_256:
3715 		group = "gcmp-256";
3716 		break;
3717 	default:
3718 		group = "";
3719 		break;
3720 	}
3721 
3722 	if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
3723 		goto nomem;
3724 
3725 	/* Pairwise */
3726 	n = 0;
3727 	if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
3728 		pairwise[n++] = "tkip";
3729 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
3730 		pairwise[n++] = "ccmp";
3731 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
3732 		pairwise[n++] = "gcmp";
3733 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
3734 		pairwise[n++] = "ccmp-256";
3735 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
3736 		pairwise[n++] = "gcmp-256";
3737 
3738 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
3739 					       pairwise, n))
3740 		goto nomem;
3741 
3742 	/* Management group (RSN only) */
3743 	if (ie_data->proto == WPA_PROTO_RSN) {
3744 		switch (ie_data->mgmt_group_cipher) {
3745 #ifdef CONFIG_IEEE80211W
3746 		case WPA_CIPHER_AES_128_CMAC:
3747 			group = "aes128cmac";
3748 			break;
3749 #endif /* CONFIG_IEEE80211W */
3750 		default:
3751 			group = "";
3752 			break;
3753 		}
3754 
3755 		if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
3756 						 group))
3757 			goto nomem;
3758 	}
3759 
3760 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
3761 	    !dbus_message_iter_close_container(iter, &variant_iter))
3762 		goto nomem;
3763 
3764 	return TRUE;
3765 
3766 nomem:
3767 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3768 	return FALSE;
3769 }
3770 
3771 
3772 /**
3773  * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
3774  * @iter: Pointer to incoming dbus message iter
3775  * @error: Location to store error on failure
3776  * @user_data: Function specific data
3777  * Returns: TRUE on success, FALSE on failure
3778  *
3779  * Getter for "WPA" property.
3780  */
wpas_dbus_getter_bss_wpa(DBusMessageIter * iter,DBusError * error,void * user_data)3781 dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
3782 				     void *user_data)
3783 {
3784 	struct bss_handler_args *args = user_data;
3785 	struct wpa_bss *res;
3786 	struct wpa_ie_data wpa_data;
3787 	const u8 *ie;
3788 
3789 	res = get_bss_helper(args, error, __func__);
3790 	if (!res)
3791 		return FALSE;
3792 
3793 	os_memset(&wpa_data, 0, sizeof(wpa_data));
3794 	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
3795 	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3796 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3797 				     "failed to parse WPA IE");
3798 		return FALSE;
3799 	}
3800 
3801 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3802 }
3803 
3804 
3805 /**
3806  * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
3807  * @iter: Pointer to incoming dbus message iter
3808  * @error: Location to store error on failure
3809  * @user_data: Function specific data
3810  * Returns: TRUE on success, FALSE on failure
3811  *
3812  * Getter for "RSN" property.
3813  */
wpas_dbus_getter_bss_rsn(DBusMessageIter * iter,DBusError * error,void * user_data)3814 dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
3815 				     void *user_data)
3816 {
3817 	struct bss_handler_args *args = user_data;
3818 	struct wpa_bss *res;
3819 	struct wpa_ie_data wpa_data;
3820 	const u8 *ie;
3821 
3822 	res = get_bss_helper(args, error, __func__);
3823 	if (!res)
3824 		return FALSE;
3825 
3826 	os_memset(&wpa_data, 0, sizeof(wpa_data));
3827 	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
3828 	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3829 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3830 				     "failed to parse RSN IE");
3831 		return FALSE;
3832 	}
3833 
3834 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3835 }
3836 
3837 
3838 /**
3839  * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
3840  * @iter: Pointer to incoming dbus message iter
3841  * @error: Location to store error on failure
3842  * @user_data: Function specific data
3843  * Returns: TRUE on success, FALSE on failure
3844  *
3845  * Getter for "WPS" property.
3846  */
wpas_dbus_getter_bss_wps(DBusMessageIter * iter,DBusError * error,void * user_data)3847 dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
3848 				     void *user_data)
3849 {
3850 	struct bss_handler_args *args = user_data;
3851 	struct wpa_bss *res;
3852 #ifdef CONFIG_WPS
3853 	struct wpabuf *wps_ie;
3854 #endif /* CONFIG_WPS */
3855 	DBusMessageIter iter_dict, variant_iter;
3856 	int wps_support = 0;
3857 	const char *type = "";
3858 
3859 	res = get_bss_helper(args, error, __func__);
3860 	if (!res)
3861 		return FALSE;
3862 
3863 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3864 					      "a{sv}", &variant_iter) ||
3865 	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3866 		goto nomem;
3867 
3868 #ifdef CONFIG_WPS
3869 	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
3870 	if (wps_ie) {
3871 		wps_support = 1;
3872 		if (wps_is_selected_pbc_registrar(wps_ie))
3873 			type = "pbc";
3874 		else if (wps_is_selected_pin_registrar(wps_ie))
3875 			type = "pin";
3876 
3877 		wpabuf_free(wps_ie);
3878 	}
3879 #endif /* CONFIG_WPS */
3880 
3881 	if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) ||
3882 	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
3883 	    !dbus_message_iter_close_container(iter, &variant_iter))
3884 		goto nomem;
3885 
3886 	return TRUE;
3887 
3888 nomem:
3889 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3890 	return FALSE;
3891 }
3892 
3893 
3894 /**
3895  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
3896  * @iter: Pointer to incoming dbus message iter
3897  * @error: Location to store error on failure
3898  * @user_data: Function specific data
3899  * Returns: TRUE on success, FALSE on failure
3900  *
3901  * Getter for "IEs" property.
3902  */
wpas_dbus_getter_bss_ies(DBusMessageIter * iter,DBusError * error,void * user_data)3903 dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
3904 				     void *user_data)
3905 {
3906 	struct bss_handler_args *args = user_data;
3907 	struct wpa_bss *res;
3908 
3909 	res = get_bss_helper(args, error, __func__);
3910 	if (!res)
3911 		return FALSE;
3912 
3913 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3914 						      res + 1, res->ie_len,
3915 						      error);
3916 }
3917 
3918 
3919 /**
3920  * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
3921  * @iter: Pointer to incoming dbus message iter
3922  * @error: Location to store error on failure
3923  * @user_data: Function specific data
3924  * Returns: TRUE on success, FALSE on failure
3925  *
3926  * Getter for BSS age
3927  */
wpas_dbus_getter_bss_age(DBusMessageIter * iter,DBusError * error,void * user_data)3928 dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
3929 				     void *user_data)
3930 {
3931 	struct bss_handler_args *args = user_data;
3932 	struct wpa_bss *res;
3933 	struct os_reltime now, diff = { 0, 0 };
3934 	u32 age;
3935 
3936 	res = get_bss_helper(args, error, __func__);
3937 	if (!res)
3938 		return FALSE;
3939 
3940 	os_get_reltime(&now);
3941 	os_reltime_sub(&now, &res->last_update, &diff);
3942 	age = diff.sec > 0 ? diff.sec : 0;
3943 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
3944 						error);
3945 }
3946 
3947 
3948 /**
3949  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
3950  * @iter: Pointer to incoming dbus message iter
3951  * @error: Location to store error on failure
3952  * @user_data: Function specific data
3953  * Returns: TRUE on success, FALSE on failure
3954  *
3955  * Getter for "enabled" property of a configured network.
3956  */
wpas_dbus_getter_enabled(DBusMessageIter * iter,DBusError * error,void * user_data)3957 dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
3958 				     void *user_data)
3959 {
3960 	struct network_handler_args *net = user_data;
3961 	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
3962 
3963 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3964 						&enabled, error);
3965 }
3966 
3967 
3968 /**
3969  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
3970  * @iter: Pointer to incoming dbus message iter
3971  * @error: Location to store error on failure
3972  * @user_data: Function specific data
3973  * Returns: TRUE on success, FALSE on failure
3974  *
3975  * Setter for "Enabled" property of a configured network.
3976  */
wpas_dbus_setter_enabled(DBusMessageIter * iter,DBusError * error,void * user_data)3977 dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
3978 				     void *user_data)
3979 {
3980 	struct network_handler_args *net = user_data;
3981 	struct wpa_supplicant *wpa_s;
3982 	struct wpa_ssid *ssid;
3983 	dbus_bool_t enable;
3984 
3985 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
3986 					      &enable))
3987 		return FALSE;
3988 
3989 	wpa_s = net->wpa_s;
3990 	ssid = net->ssid;
3991 
3992 	if (enable)
3993 		wpa_supplicant_enable_network(wpa_s, ssid);
3994 	else
3995 		wpa_supplicant_disable_network(wpa_s, ssid);
3996 
3997 	return TRUE;
3998 }
3999 
4000 
4001 /**
4002  * wpas_dbus_getter_network_properties - Get options for a configured network
4003  * @iter: Pointer to incoming dbus message iter
4004  * @error: Location to store error on failure
4005  * @user_data: Function specific data
4006  * Returns: TRUE on success, FALSE on failure
4007  *
4008  * Getter for "Properties" property of a configured network.
4009  */
wpas_dbus_getter_network_properties(DBusMessageIter * iter,DBusError * error,void * user_data)4010 dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
4011 						DBusError *error,
4012 						void *user_data)
4013 {
4014 	struct network_handler_args *net = user_data;
4015 	DBusMessageIter	variant_iter, dict_iter;
4016 	char **iterator;
4017 	char **props = wpa_config_get_all(net->ssid, 1);
4018 	dbus_bool_t success = FALSE;
4019 
4020 	if (!props) {
4021 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4022 		return FALSE;
4023 	}
4024 
4025 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
4026 					      &variant_iter) ||
4027 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
4028 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4029 		goto out;
4030 	}
4031 
4032 	iterator = props;
4033 	while (*iterator) {
4034 		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
4035 						 *(iterator + 1))) {
4036 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4037 					     "no memory");
4038 			goto out;
4039 		}
4040 		iterator += 2;
4041 	}
4042 
4043 
4044 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
4045 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
4046 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4047 		goto out;
4048 	}
4049 
4050 	success = TRUE;
4051 
4052 out:
4053 	iterator = props;
4054 	while (*iterator) {
4055 		os_free(*iterator);
4056 		iterator++;
4057 	}
4058 	os_free(props);
4059 	return success;
4060 }
4061 
4062 
4063 /**
4064  * wpas_dbus_setter_network_properties - Set options for a configured network
4065  * @iter: Pointer to incoming dbus message iter
4066  * @error: Location to store error on failure
4067  * @user_data: Function specific data
4068  * Returns: TRUE on success, FALSE on failure
4069  *
4070  * Setter for "Properties" property of a configured network.
4071  */
wpas_dbus_setter_network_properties(DBusMessageIter * iter,DBusError * error,void * user_data)4072 dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
4073 						DBusError *error,
4074 						void *user_data)
4075 {
4076 	struct network_handler_args *net = user_data;
4077 	struct wpa_ssid *ssid = net->ssid;
4078 	DBusMessageIter	variant_iter;
4079 
4080 	dbus_message_iter_recurse(iter, &variant_iter);
4081 	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
4082 }
4083 
4084 
4085 #ifdef CONFIG_AP
4086 
wpas_dbus_handler_subscribe_preq(DBusMessage * message,struct wpa_supplicant * wpa_s)4087 DBusMessage * wpas_dbus_handler_subscribe_preq(
4088 	DBusMessage *message, struct wpa_supplicant *wpa_s)
4089 {
4090 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4091 	char *name;
4092 
4093 	if (wpa_s->preq_notify_peer != NULL) {
4094 		if (os_strcmp(dbus_message_get_sender(message),
4095 			      wpa_s->preq_notify_peer) == 0)
4096 			return NULL;
4097 
4098 		return dbus_message_new_error(message,
4099 			WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
4100 			"Another application is already subscribed");
4101 	}
4102 
4103 	name = os_strdup(dbus_message_get_sender(message));
4104 	if (!name)
4105 		return wpas_dbus_error_no_memory(message);
4106 
4107 	wpa_s->preq_notify_peer = name;
4108 
4109 	/* Subscribe to clean up if application closes socket */
4110 	wpas_dbus_subscribe_noc(priv);
4111 
4112 	/*
4113 	 * Double-check it's still alive to make sure that we didn't
4114 	 * miss the NameOwnerChanged signal, e.g. while strdup'ing.
4115 	 */
4116 	if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
4117 		/*
4118 		 * Application no longer exists, clean up.
4119 		 * The return value is irrelevant now.
4120 		 *
4121 		 * Need to check if the NameOwnerChanged handling
4122 		 * already cleaned up because we have processed
4123 		 * DBus messages while checking if the name still
4124 		 * has an owner.
4125 		 */
4126 		if (!wpa_s->preq_notify_peer)
4127 			return NULL;
4128 		os_free(wpa_s->preq_notify_peer);
4129 		wpa_s->preq_notify_peer = NULL;
4130 		wpas_dbus_unsubscribe_noc(priv);
4131 	}
4132 
4133 	return NULL;
4134 }
4135 
4136 
wpas_dbus_handler_unsubscribe_preq(DBusMessage * message,struct wpa_supplicant * wpa_s)4137 DBusMessage * wpas_dbus_handler_unsubscribe_preq(
4138 	DBusMessage *message, struct wpa_supplicant *wpa_s)
4139 {
4140 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4141 
4142 	if (!wpa_s->preq_notify_peer)
4143 		return dbus_message_new_error(message,
4144 			WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
4145 			"Not subscribed");
4146 
4147 	if (os_strcmp(wpa_s->preq_notify_peer,
4148 		      dbus_message_get_sender(message)))
4149 		return dbus_message_new_error(message,
4150 			WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
4151 			"Can't unsubscribe others");
4152 
4153 	os_free(wpa_s->preq_notify_peer);
4154 	wpa_s->preq_notify_peer = NULL;
4155 	wpas_dbus_unsubscribe_noc(priv);
4156 	return NULL;
4157 }
4158 
4159 
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)4160 void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
4161 			   const u8 *addr, const u8 *dst, const u8 *bssid,
4162 			   const u8 *ie, size_t ie_len, u32 ssi_signal)
4163 {
4164 	DBusMessage *msg;
4165 	DBusMessageIter iter, dict_iter;
4166 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4167 
4168 	/* Do nothing if the control interface is not turned on */
4169 	if (priv == NULL || !wpa_s->dbus_new_path)
4170 		return;
4171 
4172 	if (wpa_s->preq_notify_peer == NULL)
4173 		return;
4174 
4175 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
4176 				      WPAS_DBUS_NEW_IFACE_INTERFACE,
4177 				      "ProbeRequest");
4178 	if (msg == NULL)
4179 		return;
4180 
4181 	dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
4182 
4183 	dbus_message_iter_init_append(msg, &iter);
4184 
4185 	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
4186 	    (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
4187 						      (const char *) addr,
4188 						      ETH_ALEN)) ||
4189 	    (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
4190 						     (const char *) dst,
4191 						     ETH_ALEN)) ||
4192 	    (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
4193 						       (const char *) bssid,
4194 						       ETH_ALEN)) ||
4195 	    (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
4196 							      (const char *) ie,
4197 							      ie_len)) ||
4198 	    (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
4199 						       ssi_signal)) ||
4200 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
4201 		goto fail;
4202 
4203 	dbus_connection_send(priv->con, msg, NULL);
4204 	goto out;
4205 fail:
4206 	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
4207 out:
4208 	dbus_message_unref(msg);
4209 }
4210 
4211 #endif /* CONFIG_AP */
4212