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