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