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