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