139287Ssos/*
239643Syokota * WPA Supplicant / dbus-based control interface
339287Ssos * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
439287Ssos *
539287Ssos * This software may be distributed under the terms of the BSD license.
639287Ssos * See README for more details.
739287Ssos */
839287Ssos
939643Syokota#include "includes.h"
1039643Syokota#include <dbus/dbus.h>
1139287Ssos
1239287Ssos#include "common.h"
1339287Ssos#include "eap_peer/eap_methods.h"
1439287Ssos#include "common/ieee802_11_defs.h"
1539643Syokota#include "eapol_supp/eapol_supp_sm.h"
1639643Syokota#include "rsn_supp/wpa.h"
1739643Syokota#include "../config.h"
1839643Syokota#include "../wpa_supplicant_i.h"
1939643Syokota#include "../driver_i.h"
2039643Syokota#include "../notify.h"
2139643Syokota#include "../wpas_glue.h"
2239643Syokota#include "../bss.h"
2339643Syokota#include "../scan.h"
2439643Syokota#include "dbus_old.h"
2539287Ssos#include "dbus_old_handlers.h"
2650477Speter#include "dbus_dict_helpers.h"
2739287Ssos
2839287Ssosextern int wpa_debug_level;
2942504Syokotaextern int wpa_debug_show_keys;
3066710Sjhbextern int wpa_debug_timestamp;
3139287Ssos
3256836Speter/**
3339287Ssos * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
3439287Ssos * @message: Pointer to incoming dbus message this error refers to
3539287Ssos * Returns: a dbus error message
3639287Ssos *
3742179Syokota * Convenience function to create and return an invalid options error
3839287Ssos */
3948104SyokotaDBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
4048104Syokota					       const char *arg)
4139287Ssos{
4248104Syokota	DBusMessage *reply;
4348104Syokota
4439287Ssos	reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
4539287Ssos				       "Did not receive correct message "
4639287Ssos				       "arguments.");
4739287Ssos	if (arg != NULL)
4839287Ssos		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
4939287Ssos					 DBUS_TYPE_INVALID);
5039287Ssos
5142504Syokota	return reply;
5242504Syokota}
5339287Ssos
5442504Syokota
5542504Syokota/**
5642504Syokota * wpas_dbus_new_success_reply - Return a new success reply message
5742504Syokota * @message: Pointer to incoming dbus message this reply refers to
5842504Syokota * Returns: a dbus message containing a single UINT32 that indicates
5942504Syokota *          success (ie, a value of 1)
6042504Syokota *
6142611Syokota * Convenience function to create and return a success reply message
6242504Syokota */
6342504SyokotaDBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
6439287Ssos{
6539287Ssos	DBusMessage *reply;
6639287Ssos	unsigned int success = 1;
6739287Ssos
6839287Ssos	reply = dbus_message_new_method_return(message);
6939287Ssos	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
7039287Ssos				 DBUS_TYPE_INVALID);
7139287Ssos	return reply;
7239287Ssos}
7339287Ssos
7439287Ssos
7539287Ssos/**
7639287Ssos * wpas_dbus_global_add_interface - Request registration of a network interface
7748399Speter * @message: Pointer to incoming dbus message
7842504Syokota * @global: %wpa_supplicant global data structure
7948399Speter * Returns: The object path of the new interface object,
8048104Syokota *          or a dbus error message with more information
8142504Syokota *
8239287Ssos * Handler function for "addInterface" method call. Handles requests
8339287Ssos * by dbus clients to register a network interface that wpa_supplicant
8439287Ssos * will manage.
8539287Ssos */
8639287SsosDBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
8739287Ssos					     struct wpa_global *global)
8839287Ssos{
8939287Ssos	char *ifname = NULL;
9039287Ssos	char *driver = NULL;
9139287Ssos	char *driver_param = NULL;
9239287Ssos	char *confname = NULL;
9339287Ssos	char *bridge_ifname = NULL;
9439287Ssos	DBusMessage *reply = NULL;
9539287Ssos	DBusMessageIter iter;
9639287Ssos
9742504Syokota	dbus_message_iter_init(message, &iter);
9848104Syokota
9942504Syokota	/* First argument: interface name (DBUS_TYPE_STRING)
10048104Syokota	 *    Required; must be non-zero length
10148104Syokota	 */
10248104Syokota	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
10348104Syokota		goto error;
10439287Ssos	dbus_message_iter_get_basic(&iter, &ifname);
10548104Syokota	if (!os_strlen(ifname))
10644846Sjlemon		goto error;
10739287Ssos
10842504Syokota	/* Second argument: dict of options */
10942504Syokota	if (dbus_message_iter_next(&iter)) {
11042504Syokota		DBusMessageIter iter_dict;
11142504Syokota		struct wpa_dbus_dict_entry entry;
11242504Syokota
11342504Syokota		if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
11442504Syokota			goto error;
11542504Syokota		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
11642504Syokota			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
11742504Syokota				goto error;
11842504Syokota			if (!strcmp(entry.key, "driver") &&
11942504Syokota			    (entry.type == DBUS_TYPE_STRING)) {
12042504Syokota				driver = os_strdup(entry.str_value);
12142504Syokota				wpa_dbus_dict_entry_clear(&entry);
12242504Syokota				if (driver == NULL)
12342504Syokota					goto error;
12442504Syokota			} else if (!strcmp(entry.key, "driver-params") &&
12542504Syokota				   (entry.type == DBUS_TYPE_STRING)) {
12648104Syokota				driver_param = os_strdup(entry.str_value);
12742504Syokota				wpa_dbus_dict_entry_clear(&entry);
12848104Syokota				if (driver_param == NULL)
12948104Syokota					goto error;
13048104Syokota			} else if (!strcmp(entry.key, "config-file") &&
13148104Syokota				   (entry.type == DBUS_TYPE_STRING)) {
13248104Syokota				confname = os_strdup(entry.str_value);
13348104Syokota				wpa_dbus_dict_entry_clear(&entry);
13439287Ssos				if (confname == NULL)
13539287Ssos					goto error;
13639287Ssos			} else if (!strcmp(entry.key, "bridge-ifname") &&
13742504Syokota				   (entry.type == DBUS_TYPE_STRING)) {
13839287Ssos				bridge_ifname = os_strdup(entry.str_value);
13939287Ssos				wpa_dbus_dict_entry_clear(&entry);
14039287Ssos				if (bridge_ifname == NULL)
14139287Ssos					goto error;
14239287Ssos			} else {
14339287Ssos				wpa_dbus_dict_entry_clear(&entry);
14448104Syokota				goto error;
14539287Ssos			}
14648104Syokota		}
14748104Syokota	}
14848104Syokota
14948104Syokota	/*
15039287Ssos	 * Try to get the wpa_supplicant record for this iface, return
15139287Ssos	 * an error if we already control it.
15239287Ssos	 */
15339287Ssos	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
15439858Syokota		reply = dbus_message_new_error(message,
15539858Syokota					       WPAS_ERROR_EXISTS_ERROR,
15639858Syokota					       "wpa_supplicant already "
15739858Syokota					       "controls this interface.");
15839287Ssos	} else {
15939287Ssos		struct wpa_supplicant *wpa_s;
16039287Ssos		struct wpa_interface iface;
16139287Ssos		os_memset(&iface, 0, sizeof(iface));
16242504Syokota		iface.ifname = ifname;
16339287Ssos		iface.driver = driver;
16439287Ssos		iface.driver_param = driver_param;
16545117Syokota		iface.confname = confname;
16639287Ssos		iface.bridge_ifname = bridge_ifname;
16742729Syokota		/* Otherwise, have wpa_supplicant attach to it. */
16842729Syokota		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
16948104Syokota			const char *path = wpa_s->dbus_path;
17048104Syokota			reply = dbus_message_new_method_return(message);
17142729Syokota			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
17242729Syokota			                         &path, DBUS_TYPE_INVALID);
17348399Speter		} else {
17448104Syokota			reply = dbus_message_new_error(message,
17548104Syokota						       WPAS_ERROR_ADD_ERROR,
17648399Speter						       "wpa_supplicant "
17739287Ssos						       "couldn't grab this "
17839287Ssos						       "interface.");
17939287Ssos		}
18039287Ssos	}
18139287Ssos
18239287Ssosout:
18339287Ssos	os_free(driver);
18439287Ssos	os_free(driver_param);
18539287Ssos	os_free(confname);
18639287Ssos	os_free(bridge_ifname);
18739287Ssos	return reply;
18843664Syokota
18950446Syokotaerror:
19048399Speter	reply = wpas_dbus_new_invalid_opts_error(message, NULL);
19148104Syokota	goto out;
19248399Speter}
19348104Syokota
19439591Syokota
19539591Syokota/**
19648104Syokota * wpas_dbus_global_remove_interface - Request deregistration of an interface
19739858Syokota * @message: Pointer to incoming dbus message
19839858Syokota * @global: wpa_supplicant global data structure
19939287Ssos * Returns: a dbus message containing a UINT32 indicating success (1) or
20039591Syokota *          failure (0), or returns a dbus error message with more information
20148104Syokota *
20248104Syokota * Handler function for "removeInterface" method call.  Handles requests
20339287Ssos * by dbus clients to deregister a network interface that wpa_supplicant
20448399Speter * currently manages.
20548104Syokota */
20648399SpeterDBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
20748104Syokota						struct wpa_global *global)
20839287Ssos{
20939287Ssos	struct wpa_supplicant *wpa_s;
21039287Ssos	char *path;
21139287Ssos	DBusMessage *reply = NULL;
21239287Ssos
21339287Ssos	if (!dbus_message_get_args(message, NULL,
21439287Ssos				   DBUS_TYPE_OBJECT_PATH, &path,
21539287Ssos				   DBUS_TYPE_INVALID)) {
21639287Ssos		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
21739287Ssos		goto out;
21839287Ssos	}
21939287Ssos
22042504Syokota	wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
22142504Syokota	if (wpa_s == NULL) {
22242504Syokota		reply = wpas_dbus_new_invalid_iface_error(message);
22342504Syokota		goto out;
22442504Syokota	}
22542504Syokota
22642504Syokota	if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
22742504Syokota		reply = wpas_dbus_new_success_reply(message);
22842504Syokota	} else {
22942504Syokota		reply = dbus_message_new_error(message,
23042504Syokota					       WPAS_ERROR_REMOVE_ERROR,
23142504Syokota					       "wpa_supplicant couldn't "
23239287Ssos					       "remove this interface.");
23339287Ssos	}
23439287Ssos
23539287Ssosout:
23639287Ssos	return reply;
23744846Sjlemon}
23839287Ssos
23939287Ssos
24039287Ssos/**
24139287Ssos * wpas_dbus_global_get_interface - Get the object path for an interface name
24239287Ssos * @message: Pointer to incoming dbus message
24344846Sjlemon * @global: %wpa_supplicant global data structure
24444866Sjlemon * Returns: The object path of the interface object,
24544846Sjlemon *          or a dbus error message with more information
24644846Sjlemon *
24750445Syokota * Handler function for "getInterface" method call. Handles requests
24839287Ssos * by dbus clients for the object path of an specific network interface.
24939287Ssos */
25039287SsosDBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
25139287Ssos					     struct wpa_global *global)
25239287Ssos{
25339287Ssos	DBusMessage *reply = NULL;
25439287Ssos	const char *ifname;
25539287Ssos	const char *path;
25639287Ssos	struct wpa_supplicant *wpa_s;
25739287Ssos
25839287Ssos	if (!dbus_message_get_args(message, NULL,
25939287Ssos	                           DBUS_TYPE_STRING, &ifname,
26039287Ssos	                           DBUS_TYPE_INVALID)) {
26139287Ssos		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
26239287Ssos		goto out;
26350445Syokota	}
26439287Ssos
26539287Ssos	wpa_s = wpa_supplicant_get_iface(global, ifname);
26639287Ssos	if (wpa_s == NULL) {
26745117Syokota		reply = wpas_dbus_new_invalid_iface_error(message);
26845117Syokota		goto out;
26945117Syokota	}
27045117Syokota
27145117Syokota	path = wpa_s->dbus_path;
27245117Syokota	reply = dbus_message_new_method_return(message);
27345117Syokota	dbus_message_append_args(reply,
27445117Syokota	                         DBUS_TYPE_OBJECT_PATH, &path,
27545117Syokota	                         DBUS_TYPE_INVALID);
27650445Syokota
27745117Syokotaout:
27845117Syokota	return reply;
27945117Syokota}
28045117Syokota
28145117Syokota
28239287Ssos/**
28339287Ssos * wpas_dbus_global_set_debugparams- Set the debug params
28439287Ssos * @message: Pointer to incoming dbus message
28539287Ssos * @global: %wpa_supplicant global data structure
28639287Ssos * Returns: a dbus message containing a UINT32 indicating success (1) or
28739287Ssos *          failure (0), or returns a dbus error message with more information
28839287Ssos *
28939287Ssos * Handler function for "setDebugParams" method call. Handles requests
29039287Ssos * by dbus clients for the object path of an specific network interface.
29150445Syokota */
29242729SyokotaDBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
29342729Syokota					       struct wpa_global *global)
29439287Ssos{
29539287Ssos	DBusMessage *reply = NULL;
29639287Ssos	int debug_level;
29742729Syokota	dbus_bool_t debug_timestamp;
29839287Ssos	dbus_bool_t debug_show_keys;
29939287Ssos
30039287Ssos	if (!dbus_message_get_args(message, NULL,
30139287Ssos	                           DBUS_TYPE_INT32, &debug_level,
30239287Ssos	                           DBUS_TYPE_BOOLEAN, &debug_timestamp,
30339287Ssos	                           DBUS_TYPE_BOOLEAN, &debug_show_keys,
30439287Ssos	                           DBUS_TYPE_INVALID)) {
30539287Ssos		return wpas_dbus_new_invalid_opts_error(message, NULL);
30639287Ssos	}
30739287Ssos
30839287Ssos	if (wpa_supplicant_set_debug_params(global, debug_level,
30944846Sjlemon					    debug_timestamp ? 1 : 0,
31044866Sjlemon					    debug_show_keys ? 1 : 0)) {
31144846Sjlemon		return wpas_dbus_new_invalid_opts_error(message, NULL);
31244846Sjlemon	}
31350445Syokota
31439287Ssos	reply = wpas_dbus_new_success_reply(message);
31539287Ssos
31642729Syokota	return reply;
31739287Ssos}
31842729Syokota
31942729Syokota
32042729Syokota/**
32139287Ssos * wpas_dbus_iface_scan - Request a wireless scan on an interface
32239287Ssos * @message: Pointer to incoming dbus message
32339287Ssos * @wpa_s: wpa_supplicant structure for a network interface
32439287Ssos * Returns: a dbus message containing a UINT32 indicating success (1) or
32539287Ssos *          failure (0)
32648104Syokota *
32748104Syokota * Handler function for "scan" method call of a network device. Requests
32848104Syokota * that wpa_supplicant perform a wireless scan as soon as possible
32948104Syokota * on a particular wireless interface.
33048104Syokota */
33148104SyokotaDBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
33248104Syokota				   struct wpa_supplicant *wpa_s)
33348104Syokota{
33448104Syokota	wpa_s->scan_req = MANUAL_SCAN_REQ;
33548104Syokota	wpa_supplicant_req_scan(wpa_s, 0, 0);
33648104Syokota	return wpas_dbus_new_success_reply(message);
33748104Syokota}
33848104Syokota
33948104Syokota
34048104Syokota/**
34148104Syokota * wpas_dbus_iface_scan_results - Get the results of a recent scan request
34248104Syokota * @message: Pointer to incoming dbus message
34350445Syokota * @wpa_s: wpa_supplicant structure for a network interface
34448104Syokota * Returns: a dbus message containing a dbus array of objects paths, or returns
34548104Syokota *          a dbus error message if not scan results could be found
34648104Syokota *
34748104Syokota * Handler function for "scanResults" method call of a network device. Returns
34848104Syokota * a dbus message containing the object paths of wireless networks found.
34948104Syokota */
35048104SyokotaDBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
35148104Syokota					   struct wpa_supplicant *wpa_s)
35248104Syokota{
35348104Syokota	DBusMessage *reply = NULL;
35448104Syokota	DBusMessageIter iter;
35548104Syokota	DBusMessageIter sub_iter;
35642729Syokota	struct wpa_bss *bss;
35739287Ssos
35839287Ssos	/* Create and initialize the return message */
35939287Ssos	reply = dbus_message_new_method_return(message);
36039287Ssos	dbus_message_iter_init_append(reply, &iter);
36139287Ssos	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
36239287Ssos					 DBUS_TYPE_OBJECT_PATH_AS_STRING,
36344846Sjlemon					 &sub_iter);
36442729Syokota
36539287Ssos	/* Loop through scan results and append each result's object path */
36642729Syokota	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
36742729Syokota		char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
36842729Syokota		char *path = path_buf;
36942729Syokota
37039287Ssos		/* Construct the object path for this network.  Note that ':'
37139287Ssos		 * is not a valid character in dbus object paths.
37239287Ssos		 */
37339287Ssos		os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
37439287Ssos			    "%s/" WPAS_DBUS_BSSIDS_PART "/"
37539287Ssos			    WPAS_DBUS_BSSID_FORMAT,
37639287Ssos			    wpa_s->dbus_path, MAC2STR(bss->bssid));
37744866Sjlemon		dbus_message_iter_append_basic(&sub_iter,
37844846Sjlemon					       DBUS_TYPE_OBJECT_PATH, &path);
37944846Sjlemon	}
38050445Syokota
38139287Ssos	dbus_message_iter_close_container(&iter, &sub_iter);
38239287Ssos
38348399Speter	return reply;
38439287Ssos}
38548104Syokota
38648104Syokota
38748104Syokota/**
38848104Syokota * wpas_dbus_bssid_properties - Return the properties of a scanned network
38948104Syokota * @message: Pointer to incoming dbus message
39048104Syokota * @wpa_s: wpa_supplicant structure for a network interface
39148104Syokota * @res: wpa_supplicant scan result for which to get properties
39248104Syokota * Returns: a dbus message containing the properties for the requested network
39348104Syokota *
39448104Syokota * Handler function for "properties" method call of a scanned network.
39548104Syokota * Returns a dbus message containing the the properties.
39648104Syokota */
39748104SyokotaDBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
39848104Syokota					 struct wpa_supplicant *wpa_s,
39948104Syokota					 struct wpa_bss *bss)
40048104Syokota{
40148104Syokota	DBusMessage *reply;
40248104Syokota	DBusMessageIter iter, iter_dict;
40348104Syokota	const u8 *ie;
40448104Syokota
40548104Syokota	/* Dump the properties into a dbus message */
40648104Syokota	reply = dbus_message_new_method_return(message);
40748104Syokota
40848104Syokota	dbus_message_iter_init_append(reply, &iter);
40948104Syokota	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
41050445Syokota		goto error;
41148104Syokota
41248399Speter	if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
41348104Syokota					     (const char *) bss->bssid,
41448104Syokota					     ETH_ALEN))
41539287Ssos		goto error;
41639287Ssos
41739287Ssos	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
41839287Ssos	if (ie) {
41939287Ssos		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
42039287Ssos						     (const char *) (ie + 2),
42139287Ssos						     ie[1]))
42239287Ssos		goto error;
42339287Ssos	}
42439287Ssos
42550445Syokota	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
42639287Ssos	if (ie) {
42750445Syokota		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
42839287Ssos						     (const char *) ie,
42939287Ssos						     ie[1] + 2))
43039287Ssos			goto error;
43139287Ssos	}
43239287Ssos
43339287Ssos	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
43444846Sjlemon	if (ie) {
43539287Ssos		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
43639287Ssos						     (const char *) ie,
43739287Ssos						     ie[1] + 2))
43839287Ssos			goto error;
43939287Ssos	}
44039287Ssos
44144846Sjlemon	ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
44244866Sjlemon	if (ie) {
44344846Sjlemon		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
44444846Sjlemon						     (const char *) ie,
44544846Sjlemon						     ie[1] + 2))
44650445Syokota			goto error;
44739287Ssos	}
44839287Ssos
44943664Syokota	if (bss->freq) {
45043664Syokota		if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
45143664Syokota						bss->freq))
45243664Syokota			goto error;
45343664Syokota	}
45443664Syokota	if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
45543664Syokota					 bss->caps))
45643664Syokota		goto error;
45743664Syokota	if (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
45843664Syokota	    !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual))
45950445Syokota		goto error;
46043664Syokota	if (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
46143664Syokota	    !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise))
46243664Syokota		goto error;
46343664Syokota	if (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
46448104Syokota	    !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level))
46550446Syokota		goto error;
46648104Syokota	if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
46748104Syokota					wpa_bss_get_max_rate(bss) * 500000))
46848104Syokota		goto error;
46948104Syokota
47048104Syokota	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
47148104Syokota		goto error;
47248104Syokota
47348104Syokota	return reply;
47448104Syokota
47548104Syokotaerror:
47648104Syokota	if (reply)
47748104Syokota		dbus_message_unref(reply);
47850446Syokota	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
47950446Syokota				      "an internal error occurred returning "
48050446Syokota				      "BSSID properties.");
48150446Syokota}
48250446Syokota
48350446Syokota
48450446Syokota/**
48548104Syokota * wpas_dbus_iface_capabilities - Return interface capabilities
48648104Syokota * @message: Pointer to incoming dbus message
48748399Speter * @wpa_s: wpa_supplicant structure for a network interface
48848104Syokota * Returns: A dbus message containing a dict of strings
48948104Syokota *
49048104Syokota * Handler function for "capabilities" method call of an interface.
49148104Syokota */
49248104SyokotaDBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
49348104Syokota					   struct wpa_supplicant *wpa_s)
49448104Syokota{
49548104Syokota	DBusMessage *reply = NULL;
49648104Syokota	struct wpa_driver_capa capa;
49748104Syokota	int res;
49850445Syokota	DBusMessageIter iter, iter_dict;
49948104Syokota	char **eap_methods;
50048104Syokota	size_t num_items;
50148104Syokota	dbus_bool_t strict = FALSE;
50248104Syokota	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
50348104Syokota
50448399Speter	if (!dbus_message_get_args(message, NULL,
50548104Syokota				   DBUS_TYPE_BOOLEAN, &strict,
50648104Syokota				   DBUS_TYPE_INVALID))
50748104Syokota		strict = FALSE;
50848104Syokota
50948104Syokota	reply = dbus_message_new_method_return(message);
51048104Syokota
51148104Syokota	dbus_message_iter_init_append(reply, &iter);
51248104Syokota	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
51348104Syokota		goto error;
51448104Syokota
51548104Syokota	/* EAP methods */
51648104Syokota	eap_methods = eap_get_names_as_string_array(&num_items);
51748104Syokota	if (eap_methods) {
51850445Syokota		dbus_bool_t success = FALSE;
51948104Syokota		size_t i = 0;
52048104Syokota
52139591Syokota		success = wpa_dbus_dict_append_string_array(
52239287Ssos			&iter_dict, "eap", (const char **) eap_methods,
52339591Syokota			num_items);
52439287Ssos
52539591Syokota		/* free returned method array */
52639591Syokota		while (eap_methods[i])
52739591Syokota			os_free(eap_methods[i++]);
52839591Syokota		os_free(eap_methods);
52939591Syokota
53039591Syokota		if (!success)
53139591Syokota			goto error;
53239591Syokota	}
53339591Syokota
53439591Syokota	res = wpa_drv_get_capa(wpa_s, &capa);
53539591Syokota
53639591Syokota	/***** pairwise cipher */
53739591Syokota	if (res < 0) {
53839591Syokota		if (!strict) {
53939591Syokota			const char *args[] = {"CCMP", "TKIP", "NONE"};
54039591Syokota			if (!wpa_dbus_dict_append_string_array(
54139591Syokota				    &iter_dict, "pairwise", args,
54239591Syokota				    sizeof(args) / sizeof(char*)))
54339591Syokota				goto error;
54439591Syokota		}
54539591Syokota	} else {
54639287Ssos		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
54739287Ssos						      &iter_dict_entry,
54839287Ssos						      &iter_dict_val,
54939287Ssos						      &iter_array))
55039287Ssos			goto error;
55139287Ssos
55239287Ssos		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
55342235Sdes			if (!wpa_dbus_dict_string_array_add_element(
55439287Ssos				    &iter_array, "CCMP"))
55539287Ssos				goto error;
55639287Ssos		}
55739287Ssos
55839287Ssos		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
55939287Ssos			if (!wpa_dbus_dict_string_array_add_element(
56039287Ssos				    &iter_array, "TKIP"))
56139287Ssos				goto error;
56239287Ssos		}
56339287Ssos
56439287Ssos		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
56548104Syokota			if (!wpa_dbus_dict_string_array_add_element(
56648104Syokota				    &iter_array, "NONE"))
56748104Syokota				goto error;
56848104Syokota		}
56948104Syokota
57048104Syokota		if (!wpa_dbus_dict_end_string_array(&iter_dict,
57148104Syokota						    &iter_dict_entry,
57248104Syokota						    &iter_dict_val,
57348104Syokota						    &iter_array))
57448104Syokota			goto error;
57548104Syokota	}
57648104Syokota
57748104Syokota	/***** group cipher */
57848104Syokota	if (res < 0) {
57948104Syokota		if (!strict) {
58048104Syokota			const char *args[] = {
58148104Syokota				"CCMP", "TKIP", "WEP104", "WEP40"
58248104Syokota			};
58348104Syokota			if (!wpa_dbus_dict_append_string_array(
58448104Syokota				    &iter_dict, "group", args,
58548104Syokota				    sizeof(args) / sizeof(char*)))
58648104Syokota				goto error;
58748104Syokota		}
58839858Syokota	} else {
58939858Syokota		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
59039858Syokota						      &iter_dict_entry,
59139858Syokota						      &iter_dict_val,
59239858Syokota						      &iter_array))
59339858Syokota			goto error;
59439858Syokota
59539858Syokota		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
59639858Syokota			if (!wpa_dbus_dict_string_array_add_element(
59739858Syokota				    &iter_array, "CCMP"))
59839858Syokota				goto error;
59939858Syokota		}
60039858Syokota
60139287Ssos		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
60239287Ssos			if (!wpa_dbus_dict_string_array_add_element(
60339287Ssos				    &iter_array, "TKIP"))
60445196Syokota				goto error;
60539287Ssos		}
60639287Ssos
60748104Syokota		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
60845196Syokota			if (!wpa_dbus_dict_string_array_add_element(
60939287Ssos				    &iter_array, "WEP104"))
61039287Ssos				goto error;
61139287Ssos		}
61239287Ssos
61339287Ssos		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
61439287Ssos			if (!wpa_dbus_dict_string_array_add_element(
61539287Ssos				    &iter_array, "WEP40"))
61639287Ssos				goto error;
61739287Ssos		}
61848104Syokota
61939287Ssos		if (!wpa_dbus_dict_end_string_array(&iter_dict,
62039287Ssos						    &iter_dict_entry,
62145196Syokota						    &iter_dict_val,
62239287Ssos						    &iter_array))
62345196Syokota			goto error;
62439744Sache	}
62545196Syokota
62644846Sjlemon	/***** key management */
62744846Sjlemon	if (res < 0) {
62850445Syokota		if (!strict) {
62939287Ssos			const char *args[] = {
63045196Syokota				"WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
63139287Ssos				"NONE"
63242504Syokota			};
63342504Syokota			if (!wpa_dbus_dict_append_string_array(
63439287Ssos				    &iter_dict, "key_mgmt", args,
63542504Syokota				    sizeof(args) / sizeof(char*)))
63639287Ssos				goto error;
63739287Ssos		}
63848104Syokota	} else {
63948104Syokota		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
64048104Syokota						      &iter_dict_entry,
64148104Syokota						      &iter_dict_val,
64248104Syokota						      &iter_array))
64348104Syokota			goto error;
64448104Syokota
64548104Syokota		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
64648104Syokota							    "NONE"))
64739287Ssos			goto error;
64839858Syokota
64939858Syokota		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
65039858Syokota							    "IEEE8021X"))
65139858Syokota			goto error;
65239858Syokota
65339858Syokota		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
65439858Syokota				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
65539858Syokota			if (!wpa_dbus_dict_string_array_add_element(
65639858Syokota				    &iter_array, "WPA-EAP"))
65739858Syokota				goto error;
65839858Syokota		}
65939858Syokota
66039858Syokota		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
66139858Syokota				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
66239858Syokota			if (!wpa_dbus_dict_string_array_add_element(
66339287Ssos				    &iter_array, "WPA-PSK"))
66439858Syokota				goto error;
66539858Syokota		}
66639858Syokota
66739858Syokota		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
66839858Syokota			if (!wpa_dbus_dict_string_array_add_element(
66939858Syokota				    &iter_array, "WPA-NONE"))
67039858Syokota				goto error;
67139287Ssos		}
67239287Ssos
67339287Ssos		if (!wpa_dbus_dict_end_string_array(&iter_dict,
67439287Ssos						    &iter_dict_entry,
67539287Ssos						    &iter_dict_val,
67639287Ssos						    &iter_array))
67739287Ssos			goto error;
67839287Ssos	}
67939287Ssos
68039287Ssos	/***** WPA protocol */
68167816Sjhb	if (res < 0) {
68266710Sjhb		if (!strict) {
68366710Sjhb			const char *args[] = { "RSN", "WPA" };
68466710Sjhb			if (!wpa_dbus_dict_append_string_array(
68566710Sjhb				    &iter_dict, "proto", args,
68666710Sjhb				    sizeof(args) / sizeof(char*)))
68766710Sjhb				goto error;
68866710Sjhb		}
68939287Ssos	} else {
69066710Sjhb		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
69139287Ssos						      &iter_dict_entry,
69239287Ssos						      &iter_dict_val,
69348104Syokota						      &iter_array))
69448104Syokota			goto error;
69548104Syokota
69648104Syokota		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
69748104Syokota				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
69848104Syokota			if (!wpa_dbus_dict_string_array_add_element(
69948104Syokota				    &iter_array, "RSN"))
70050445Syokota				goto error;
70148104Syokota		}
70248104Syokota
70348104Syokota		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
70448104Syokota				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
70548104Syokota			if (!wpa_dbus_dict_string_array_add_element(
70648104Syokota				    &iter_array, "WPA"))
70748104Syokota				goto error;
70848104Syokota		}
70966710Sjhb
71066710Sjhb		if (!wpa_dbus_dict_end_string_array(&iter_dict,
71166710Sjhb						    &iter_dict_entry,
71266710Sjhb						    &iter_dict_val,
71366710Sjhb						    &iter_array))
71439287Ssos			goto error;
71539287Ssos	}
71639287Ssos
71739287Ssos	/***** auth alg */
71839287Ssos	if (res < 0) {
71939287Ssos		if (!strict) {
72039287Ssos			const char *args[] = { "OPEN", "SHARED", "LEAP" };
72139287Ssos			if (!wpa_dbus_dict_append_string_array(
72239287Ssos				    &iter_dict, "auth_alg", args,
72339287Ssos				    sizeof(args) / sizeof(char*)))
72439287Ssos				goto error;
72539858Syokota		}
72639858Syokota	} else {
72748104Syokota		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
72848104Syokota						      &iter_dict_entry,
72948104Syokota						      &iter_dict_val,
73048104Syokota						      &iter_array))
73143664Syokota			goto error;
73248104Syokota
73348104Syokota		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
73448104Syokota			if (!wpa_dbus_dict_string_array_add_element(
73543664Syokota				    &iter_array, "OPEN"))
73643664Syokota				goto error;
73748104Syokota		}
73848104Syokota
73943664Syokota		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
74048104Syokota			if (!wpa_dbus_dict_string_array_add_element(
74148104Syokota				    &iter_array, "SHARED"))
74248104Syokota				goto error;
74348104Syokota		}
74448104Syokota
74548104Syokota		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
74648104Syokota			if (!wpa_dbus_dict_string_array_add_element(
74748104Syokota				    &iter_array, "LEAP"))
74848104Syokota				goto error;
74948104Syokota		}
75048104Syokota
75148104Syokota		if (!wpa_dbus_dict_end_string_array(&iter_dict,
75248104Syokota						    &iter_dict_entry,
75348104Syokota						    &iter_dict_val,
75448104Syokota						    &iter_array))
75548104Syokota			goto error;
75648104Syokota	}
75748104Syokota
75848104Syokota	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
75948104Syokota		goto error;
76048104Syokota
76148104Syokota	return reply;
76248104Syokota
76348104Syokotaerror:
76448104Syokota	if (reply)
76548104Syokota		dbus_message_unref(reply);
76648104Syokota	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
76748104Syokota				      "an internal error occurred returning "
76848104Syokota				      "interface capabilities.");
76948104Syokota}
77048104Syokota
77148104Syokota
77248104Syokota/**
77348104Syokota * wpas_dbus_iface_add_network - Add a new configured network
77448104Syokota * @message: Pointer to incoming dbus message
77548104Syokota * @wpa_s: wpa_supplicant structure for a network interface
77648104Syokota * Returns: A dbus message containing the object path of the new network
77739591Syokota *
77839591Syokota * Handler function for "addNetwork" method call of a network interface.
77939287Ssos */
78039287SsosDBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
78139287Ssos					  struct wpa_supplicant *wpa_s)
78239287Ssos{
78339287Ssos	DBusMessage *reply = NULL;
78439287Ssos	struct wpa_ssid *ssid;
78539858Syokota	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
78639858Syokota
78739287Ssos	ssid = wpa_config_add_network(wpa_s->conf);
78839287Ssos	if (ssid == NULL) {
78939287Ssos		reply = dbus_message_new_error(message,
79039591Syokota					       WPAS_ERROR_ADD_NETWORK_ERROR,
79139287Ssos					       "wpa_supplicant could not add "
79239287Ssos					       "a network on this interface.");
79339287Ssos		goto out;
79439287Ssos	}
79539287Ssos	wpas_notify_network_added(wpa_s, ssid);
79639287Ssos	ssid->disabled = 1;
79739287Ssos	wpa_config_set_network_defaults(ssid);
79839287Ssos
79948104Syokota	/* Construct the object path for this network. */
80048104Syokota	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
80148104Syokota		    "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
80248104Syokota		    wpa_s->dbus_path, ssid->id);
80348104Syokota
80448104Syokota	reply = dbus_message_new_method_return(message);
80548104Syokota	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
80648104Syokota				 &path, DBUS_TYPE_INVALID);
80748104Syokota
80848104Syokotaout:
80948104Syokota	return reply;
81048104Syokota}
81148104Syokota
81248104Syokota
81348104Syokota/**
81448104Syokota * wpas_dbus_iface_remove_network - Remove a configured network
81548104Syokota * @message: Pointer to incoming dbus message
81648104Syokota * @wpa_s: wpa_supplicant structure for a network interface
81748104Syokota * Returns: A dbus message containing a UINT32 indicating success (1) or
81848104Syokota *          failure (0)
81948104Syokota *
82048104Syokota * Handler function for "removeNetwork" method call of a network interface.
82148104Syokota */
82248104SyokotaDBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
82342504Syokota					     struct wpa_supplicant *wpa_s)
82439287Ssos{
82539287Ssos	DBusMessage *reply = NULL;
82642504Syokota	const char *op;
82739287Ssos	char *iface = NULL, *net_id = NULL;
82842504Syokota	int id;
82939287Ssos	struct wpa_ssid *ssid;
83042504Syokota
83139287Ssos	if (!dbus_message_get_args(message, NULL,
83239287Ssos	                           DBUS_TYPE_OBJECT_PATH, &op,
83342504Syokota	                           DBUS_TYPE_INVALID)) {
83442504Syokota		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
83542504Syokota		goto out;
83642504Syokota	}
83742504Syokota
83842504Syokota	/* Extract the network ID */
83942504Syokota	iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
84042504Syokota	if (iface == NULL) {
84142504Syokota		reply = wpas_dbus_new_invalid_network_error(message);
84242504Syokota		goto out;
84342504Syokota	}
84442504Syokota
84542504Syokota	/* Ensure the network is actually a child of this interface */
84642504Syokota	if (os_strcmp(iface, wpa_s->dbus_path) != 0) {
84739287Ssos		reply = wpas_dbus_new_invalid_network_error(message);
84842504Syokota		goto out;
84942504Syokota	}
85042504Syokota
85142504Syokota	id = strtoul(net_id, NULL, 10);
85242504Syokota	ssid = wpa_config_get_network(wpa_s->conf, id);
85342504Syokota	if (ssid == NULL) {
85442504Syokota		reply = wpas_dbus_new_invalid_network_error(message);
85542504Syokota		goto out;
85642504Syokota	}
85742504Syokota
85842504Syokota	wpas_notify_network_removed(wpa_s, ssid);
85942504Syokota
86042504Syokota	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
86142504Syokota		reply = dbus_message_new_error(message,
86242504Syokota					       WPAS_ERROR_REMOVE_NETWORK_ERROR,
86342504Syokota					       "error removing the specified "
86442504Syokota					       "on this interface.");
86542504Syokota		goto out;
86642504Syokota	}
86742504Syokota
86842504Syokota	if (ssid == wpa_s->current_ssid)
86942504Syokota		wpa_supplicant_deauthenticate(wpa_s,
87042504Syokota					      WLAN_REASON_DEAUTH_LEAVING);
87142504Syokota	reply = wpas_dbus_new_success_reply(message);
87242504Syokota
87342504Syokotaout:
87442504Syokota	os_free(iface);
87542504Syokota	os_free(net_id);
87642504Syokota	return reply;
87742504Syokota}
87842504Syokota
87942504Syokota
88042504Syokotastatic const char *dont_quote[] = {
88142504Syokota	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
88242504Syokota	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
88342504Syokota	"bssid", NULL
88442504Syokota};
88542504Syokota
88642504Syokota
88742504Syokotastatic dbus_bool_t should_quote_opt(const char *key)
88842504Syokota{
88939287Ssos	int i = 0;
89039287Ssos	while (dont_quote[i] != NULL) {
89148399Speter		if (strcmp(key, dont_quote[i]) == 0)
89242504Syokota			return FALSE;
89342504Syokota		i++;
89439287Ssos	}
89542504Syokota	return TRUE;
89639287Ssos}
89748399Speter
89839287Ssos
89939287Ssos/**
90048104Syokota * wpas_dbus_iface_set_network - Set options for a configured network
90148104Syokota * @message: Pointer to incoming dbus message
90248104Syokota * @wpa_s: wpa_supplicant structure for a network interface
90348104Syokota * @ssid: wpa_ssid structure for a configured network
90448104Syokota * Returns: a dbus message containing a UINT32 indicating success (1) or
90548104Syokota *          failure (0)
90642504Syokota *
90739287Ssos * Handler function for "set" method call of a configured network.
90842504Syokota */
90942504SyokotaDBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
91042504Syokota					  struct wpa_supplicant *wpa_s,
91142504Syokota					  struct wpa_ssid *ssid)
91242504Syokota{
91342504Syokota	DBusMessage *reply = NULL;
91442504Syokota	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
91542504Syokota	DBusMessageIter	iter, iter_dict;
91642504Syokota
91742504Syokota	dbus_message_iter_init(message, &iter);
91842504Syokota
91942504Syokota	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
92039287Ssos		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
92139287Ssos		goto out;
92242504Syokota	}
92339287Ssos
92439287Ssos	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
92542504Syokota		char *value = NULL;
92639287Ssos		size_t size = 50;
92739591Syokota		int ret;
92839591Syokota
92939591Syokota		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
93039287Ssos			reply = wpas_dbus_new_invalid_opts_error(message,
93139287Ssos								 NULL);
93239287Ssos			goto out;
93339287Ssos		}
93439287Ssos
93539287Ssos		/* Type conversions, since wpa_supplicant wants strings */
93639287Ssos		if (entry.type == DBUS_TYPE_ARRAY &&
93739287Ssos		    entry.array_type == DBUS_TYPE_BYTE) {
93839287Ssos			if (entry.array_len <= 0)
93939287Ssos				goto error;
94039287Ssos
94139287Ssos			size = entry.array_len * 2 + 1;
94242504Syokota			value = os_zalloc(size);
94339287Ssos			if (value == NULL)
94439287Ssos				goto error;
94539287Ssos			ret = wpa_snprintf_hex(value, size,
94654258Syokota					       (u8 *) entry.bytearray_value,
94754258Syokota					       entry.array_len);
94842504Syokota			if (ret <= 0)
94954258Syokota				goto error;
95039287Ssos		} else if (entry.type == DBUS_TYPE_STRING) {
95139287Ssos			if (should_quote_opt(entry.key)) {
95239287Ssos				size = os_strlen(entry.str_value);
95339287Ssos				/* Zero-length option check */
95439287Ssos				if (size <= 0)
95539287Ssos					goto error;
95639287Ssos				size += 3;  /* For quotes and terminator */
95739287Ssos				value = os_zalloc(size);
95839287Ssos				if (value == NULL)
95939287Ssos					goto error;
96039287Ssos				ret = os_snprintf(value, size, "\"%s\"",
96139287Ssos						  entry.str_value);
96239287Ssos				if (ret < 0 || (size_t) ret != (size - 1))
96339287Ssos					goto error;
96439287Ssos			} else {
96539287Ssos				value = os_strdup(entry.str_value);
96639287Ssos				if (value == NULL)
96739287Ssos					goto error;
96839287Ssos			}
96939287Ssos		} else if (entry.type == DBUS_TYPE_UINT32) {
97039287Ssos			value = os_zalloc(size);
97139287Ssos			if (value == NULL)
97239287Ssos				goto error;
97339287Ssos			ret = os_snprintf(value, size, "%u",
97454258Syokota					  entry.uint32_value);
97554258Syokota			if (ret <= 0)
97639287Ssos				goto error;
97754258Syokota		} else if (entry.type == DBUS_TYPE_INT32) {
97839287Ssos			value = os_zalloc(size);
97939287Ssos			if (value == NULL)
98039287Ssos				goto error;
98142504Syokota			ret = os_snprintf(value, size, "%d",
98239287Ssos					  entry.int32_value);
98339287Ssos			if (ret <= 0)
98448104Syokota				goto error;
98539287Ssos		} else
98642504Syokota			goto error;
98742504Syokota
98839287Ssos		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
98948104Syokota			goto error;
99048104Syokota
99142504Syokota		if ((os_strcmp(entry.key, "psk") == 0 &&
99239287Ssos		     value[0] == '"' && ssid->ssid_len) ||
99348104Syokota		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
99439287Ssos			wpa_config_update_psk(ssid);
99539287Ssos		else if (os_strcmp(entry.key, "priority") == 0)
99639287Ssos			wpa_config_update_prio_list(wpa_s->conf);
99748104Syokota
99848104Syokota		os_free(value);
99948104Syokota		wpa_dbus_dict_entry_clear(&entry);
100048104Syokota		continue;
100148104Syokota
100239287Ssos	error:
100348104Syokota		os_free(value);
100442504Syokota		reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
100548104Syokota		wpa_dbus_dict_entry_clear(&entry);
100648104Syokota		break;
100748104Syokota	}
100848104Syokota
100948104Syokota	if (!reply)
101048104Syokota		reply = wpas_dbus_new_success_reply(message);
101148104Syokota
101248104Syokotaout:
101339287Ssos	return reply;
101439287Ssos}
101539287Ssos
101639287Ssos
101742504Syokota/**
101839287Ssos * wpas_dbus_iface_enable_network - Mark a configured network as enabled
101939287Ssos * @message: Pointer to incoming dbus message
102039287Ssos * @wpa_s: wpa_supplicant structure for a network interface
102142504Syokota * @ssid: wpa_ssid structure for a configured network
102239287Ssos * Returns: A dbus message containing a UINT32 indicating success (1) or
102339287Ssos *          failure (0)
102439287Ssos *
102542504Syokota * Handler function for "enable" method call of a configured network.
102639287Ssos */
102739287SsosDBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
102848104Syokota					     struct wpa_supplicant *wpa_s,
102948104Syokota					     struct wpa_ssid *ssid)
103048104Syokota{
103139287Ssos	wpa_supplicant_enable_network(wpa_s, ssid);
103248104Syokota	return wpas_dbus_new_success_reply(message);
103339287Ssos}
103439287Ssos
103548104Syokota
103648104Syokota/**
103748104Syokota * wpas_dbus_iface_disable_network - Mark a configured network as disabled
103848104Syokota * @message: Pointer to incoming dbus message
103942504Syokota * @wpa_s: wpa_supplicant structure for a network interface
104039287Ssos * @ssid: wpa_ssid structure for a configured network
104139287Ssos * Returns: A dbus message containing a UINT32 indicating success (1) or
104239287Ssos *          failure (0)
104339287Ssos *
104439287Ssos * Handler function for "disable" method call of a configured network.
104539287Ssos */
104639287SsosDBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
104742504Syokota					      struct wpa_supplicant *wpa_s,
104848104Syokota					      struct wpa_ssid *ssid)
104948104Syokota{
105048104Syokota	wpa_supplicant_disable_network(wpa_s, ssid);
105148104Syokota	return wpas_dbus_new_success_reply(message);
105248104Syokota}
105348104Syokota
105448104Syokota
105548104Syokota/**
105648104Syokota * wpas_dbus_iface_select_network - Attempt association with a configured network
105748104Syokota * @message: Pointer to incoming dbus message
105848104Syokota * @wpa_s: wpa_supplicant structure for a network interface
105948104Syokota * Returns: A dbus message containing a UINT32 indicating success (1) or
106039287Ssos *          failure (0)
106139287Ssos *
106248104Syokota * Handler function for "selectNetwork" method call of network interface.
106348104Syokota */
106448104SyokotaDBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
106539287Ssos					     struct wpa_supplicant *wpa_s)
106648104Syokota{
106743664Syokota	DBusMessage *reply = NULL;
106843674Syokota	const char *op;
106943674Syokota	struct wpa_ssid *ssid;
107043674Syokota	char *iface_obj_path = NULL;
107143674Syokota	char *network = NULL;
107243674Syokota
107343674Syokota	if (os_strlen(dbus_message_get_signature(message)) == 0) {
107443674Syokota		/* Any network */
107543674Syokota		ssid = NULL;
107643674Syokota	} else {
107743674Syokota		int nid;
107843674Syokota
107943674Syokota		if (!dbus_message_get_args(message, NULL,
108043674Syokota					   DBUS_TYPE_OBJECT_PATH, &op,
108143674Syokota					   DBUS_TYPE_INVALID)) {
108243674Syokota			reply = wpas_dbus_new_invalid_opts_error(message,
108343674Syokota								 NULL);
108443674Syokota			goto out;
108543674Syokota		}
108643674Syokota
108743674Syokota		/* Extract the network number */
108843674Syokota		iface_obj_path = wpas_dbus_decompose_object_path(op,
108948104Syokota								 &network,
109048104Syokota								 NULL);
109143664Syokota		if (iface_obj_path == NULL) {
109243664Syokota			reply = wpas_dbus_new_invalid_iface_error(message);
109343674Syokota			goto out;
109443664Syokota		}
109543674Syokota		/* Ensure the object path really points to this interface */
109639287Ssos		if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
109742504Syokota			reply = wpas_dbus_new_invalid_network_error(message);
109843674Syokota			goto out;
109942504Syokota		}
110039287Ssos
110139287Ssos		nid = strtoul(network, NULL, 10);
110239287Ssos		if (errno == EINVAL) {
110339287Ssos			reply = wpas_dbus_new_invalid_network_error(message);
110442504Syokota			goto out;
110542504Syokota		}
110639287Ssos
110742504Syokota		ssid = wpa_config_get_network(wpa_s->conf, nid);
110839287Ssos		if (ssid == NULL) {
110939287Ssos			reply = wpas_dbus_new_invalid_network_error(message);
111039287Ssos			goto out;
111142504Syokota		}
111242504Syokota	}
111339287Ssos
111442504Syokota	/* Finally, associate with the network */
111539287Ssos	wpa_supplicant_select_network(wpa_s, ssid);
111639287Ssos
111739287Ssos	reply = wpas_dbus_new_success_reply(message);
111842504Syokota
111939287Ssosout:
112042504Syokota	os_free(iface_obj_path);
112139287Ssos	os_free(network);
112239287Ssos	return reply;
112339287Ssos}
112442504Syokota
112539287Ssos
112642729Syokota/**
112742729Syokota * wpas_dbus_iface_disconnect - Terminate the current connection
112839287Ssos * @message: Pointer to incoming dbus message
112945117Syokota * @wpa_s: wpa_supplicant structure for a network interface
113045117Syokota * Returns: A dbus message containing a UINT32 indicating success (1) or
113145117Syokota *          failure (0)
113242729Syokota *
113342729Syokota * Handler function for "disconnect" method call of network interface.
113442729Syokota */
113545117SyokotaDBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
113645117Syokota					 struct wpa_supplicant *wpa_s)
113742729Syokota{
113842729Syokota	wpa_s->disconnected = 1;
113942729Syokota	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
114039287Ssos
114139287Ssos	return wpas_dbus_new_success_reply(message);
114239287Ssos}
114342504Syokota
114439287Ssos
114545117Syokota/**
114642729Syokota * wpas_dbus_iface_set_ap_scan - Control roaming mode
114742729Syokota * @message: Pointer to incoming dbus message
114839287Ssos * @wpa_s: wpa_supplicant structure for a network interface
114942729Syokota * Returns: A dbus message containing a UINT32 indicating success (1) or
115045117Syokota *          failure (0)
115142729Syokota *
115242729Syokota * Handler function for "setAPScan" method call.
115342729Syokota */
115445117SyokotaDBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
115545117Syokota					  struct wpa_supplicant *wpa_s)
115642729Syokota{
115745117Syokota	DBusMessage *reply = NULL;
115842729Syokota	dbus_uint32_t ap_scan = 1;
115942729Syokota
116039287Ssos	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
116139287Ssos				   DBUS_TYPE_INVALID)) {
116239287Ssos		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
116342504Syokota		goto out;
116439287Ssos	}
116542504Syokota
116639287Ssos	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
116739287Ssos		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
116839287Ssos		goto out;
116942504Syokota	}
117039287Ssos
117142504Syokota	reply = wpas_dbus_new_success_reply(message);
117242504Syokota
117339287Ssosout:
117439287Ssos	return reply;
117539287Ssos}
117639287Ssos
117739287Ssos
117839287Ssos/**
117939287Ssos * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
118039287Ssos * @message: Pointer to incoming dbus message
118139287Ssos * @wpa_s: wpa_supplicant structure for a network interface
118239287Ssos * Returns: A dbus message containing a UINT32 indicating success (1) or
118339287Ssos *          failure (0)
118439287Ssos *
118539287Ssos * Handler function for "setSmartcardModules" method call.
118639287Ssos */
118739287SsosDBusMessage * wpas_dbus_iface_set_smartcard_modules(
118842504Syokota	DBusMessage *message, struct wpa_supplicant *wpa_s)
118939287Ssos{
119042504Syokota	DBusMessageIter iter, iter_dict;
119142504Syokota	char *opensc_engine_path = NULL;
119239287Ssos	char *pkcs11_engine_path = NULL;
119339287Ssos	char *pkcs11_module_path = NULL;
119439287Ssos	struct wpa_dbus_dict_entry entry;
119539287Ssos
119639287Ssos	if (!dbus_message_iter_init(message, &iter))
119748399Speter		goto error;
119839287Ssos
119948104Syokota	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
120048104Syokota		goto error;
120148104Syokota
120248104Syokota	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
120348104Syokota		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
120448104Syokota			goto error;
120548104Syokota		if (!strcmp(entry.key, "opensc_engine_path") &&
120648104Syokota		    (entry.type == DBUS_TYPE_STRING)) {
120748104Syokota			opensc_engine_path = os_strdup(entry.str_value);
120850445Syokota			if (opensc_engine_path == NULL)
120948104Syokota				goto error;
121048104Syokota		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
121148104Syokota			   (entry.type == DBUS_TYPE_STRING)) {
121248104Syokota			pkcs11_engine_path = os_strdup(entry.str_value);
121348399Speter			if (pkcs11_engine_path == NULL)
121448104Syokota				goto error;
121548104Syokota		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
121642504Syokota				 (entry.type == DBUS_TYPE_STRING)) {
121739287Ssos			pkcs11_module_path = os_strdup(entry.str_value);
121839287Ssos			if (pkcs11_module_path == NULL)
121939287Ssos				goto error;
122039287Ssos		} else {
122139287Ssos			wpa_dbus_dict_entry_clear(&entry);
122239287Ssos			goto error;
122339287Ssos		}
122439287Ssos		wpa_dbus_dict_entry_clear(&entry);
122539287Ssos	}
122639287Ssos
122742504Syokota	os_free(wpa_s->conf->opensc_engine_path);
122842504Syokota	wpa_s->conf->opensc_engine_path = opensc_engine_path;
122939287Ssos	os_free(wpa_s->conf->pkcs11_engine_path);
123048104Syokota	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
123148104Syokota	os_free(wpa_s->conf->pkcs11_module_path);
123248104Syokota	wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
123348104Syokota
123448104Syokota	wpa_sm_set_eapol(wpa_s->wpa, NULL);
123539287Ssos	eapol_sm_deinit(wpa_s->eapol);
123648104Syokota	wpa_s->eapol = NULL;
123739287Ssos	wpa_supplicant_init_eapol(wpa_s);
123839287Ssos	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
123939287Ssos
124048104Syokota	return wpas_dbus_new_success_reply(message);
124139287Ssos
124250445Syokotaerror:
124343664Syokota	os_free(opensc_engine_path);
124443664Syokota	os_free(pkcs11_engine_path);
124543664Syokota	os_free(pkcs11_module_path);
124643664Syokota	return wpas_dbus_new_invalid_opts_error(message, NULL);
124748104Syokota}
124843664Syokota
124948104Syokota
125043664Syokota/**
125139287Ssos * wpas_dbus_iface_get_state - Get interface state
125239287Ssos * @message: Pointer to incoming dbus message
125339287Ssos * @wpa_s: wpa_supplicant structure for a network interface
125442504Syokota * Returns: A dbus message containing a STRING representing the current
125539287Ssos *          interface state
125642504Syokota *
125739287Ssos * Handler function for "state" method call.
125839287Ssos */
125939287SsosDBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
126042504Syokota					struct wpa_supplicant *wpa_s)
126139287Ssos{
126242504Syokota	DBusMessage *reply = NULL;
126339287Ssos	const char *str_state;
126439287Ssos
126539287Ssos	reply = dbus_message_new_method_return(message);
126642504Syokota	if (reply != NULL) {
126742504Syokota		str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
126839287Ssos		dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
126942504Syokota					 DBUS_TYPE_INVALID);
127042504Syokota	}
127142504Syokota
127242504Syokota	return reply;
127342504Syokota}
127448104Syokota
127542504Syokota
127648104Syokota/**
127748104Syokota * wpas_dbus_iface_get_scanning - Get interface scanning state
127842504Syokota * @message: Pointer to incoming dbus message
127942504Syokota * @wpa_s: wpa_supplicant structure for a network interface
128042504Syokota * Returns: A dbus message containing whether the interface is scanning
128148104Syokota *
128242504Syokota * Handler function for "scanning" method call.
128348104Syokota */
128448104SyokotaDBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
128548104Syokota					   struct wpa_supplicant *wpa_s)
128642504Syokota{
128739287Ssos	DBusMessage *reply = NULL;
128848104Syokota	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
128948104Syokota
129048104Syokota	reply = dbus_message_new_method_return(message);
129148104Syokota	if (reply != NULL) {
129248104Syokota		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
129348104Syokota					 DBUS_TYPE_INVALID);
129448104Syokota	} else {
129548104Syokota		wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
129648104Syokota			   "scanning state");
129748104Syokota	}
129848104Syokota
129948104Syokota	return reply;
130048104Syokota}
130148104Syokota
130248104Syokota
130348104Syokota/**
130448104Syokota * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
130548104Syokota * @message: Pointer to incoming dbus message
130648104Syokota * @wpa_s: %wpa_supplicant data structure
130748104Syokota * Returns: A dbus message containing a UINT32 indicating success (1) or
130848104Syokota *          failure (0)
130948104Syokota *
131048104Syokota * Asks wpa_supplicant to internally store a one or more binary blobs.
131148104Syokota */
131248104SyokotaDBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
131348104Syokota					struct wpa_supplicant *wpa_s)
131448104Syokota{
131548104Syokota	DBusMessage *reply = NULL;
131648104Syokota	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
131748104Syokota	DBusMessageIter	iter, iter_dict;
131848104Syokota
131948104Syokota	dbus_message_iter_init(message, &iter);
132048104Syokota
132148104Syokota	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
132248104Syokota		return wpas_dbus_new_invalid_opts_error(message, NULL);
132348104Syokota
132448104Syokota	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
132548104Syokota		struct wpa_config_blob *blob;
132648104Syokota
132748104Syokota		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
132848104Syokota			reply = wpas_dbus_new_invalid_opts_error(message,
132948104Syokota								 NULL);
133048104Syokota			break;
133148104Syokota		}
133248104Syokota
133348104Syokota		if (entry.type != DBUS_TYPE_ARRAY ||
133448104Syokota		    entry.array_type != DBUS_TYPE_BYTE) {
133548104Syokota			reply = wpas_dbus_new_invalid_opts_error(
133648104Syokota				message, "Byte array expected.");
133748104Syokota			break;
133848104Syokota		}
133948104Syokota
134048104Syokota		if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
134148104Syokota		    !strlen(entry.key)) {
134248104Syokota			reply = wpas_dbus_new_invalid_opts_error(
134348104Syokota				message, "Invalid array size.");
134448104Syokota			break;
134548104Syokota		}
134648104Syokota
134748104Syokota		blob = os_zalloc(sizeof(*blob));
134848104Syokota		if (blob == NULL) {
134948104Syokota			reply = dbus_message_new_error(
135048104Syokota				message, WPAS_ERROR_ADD_ERROR,
135148104Syokota				"Not enough memory to add blob.");
135248104Syokota			break;
135348104Syokota		}
135448104Syokota		blob->data = os_zalloc(entry.array_len);
135548104Syokota		if (blob->data == NULL) {
135648104Syokota			reply = dbus_message_new_error(
135748104Syokota				message, WPAS_ERROR_ADD_ERROR,
135848104Syokota				"Not enough memory to add blob data.");
135948104Syokota			os_free(blob);
136048104Syokota			break;
136148104Syokota		}
136248104Syokota
136348104Syokota		blob->name = os_strdup(entry.key);
136448104Syokota		blob->len = entry.array_len;
136548104Syokota		os_memcpy(blob->data, (u8 *) entry.bytearray_value,
136648104Syokota				entry.array_len);
136748104Syokota		if (blob->name == NULL || blob->data == NULL) {
136848104Syokota			wpa_config_free_blob(blob);
136948104Syokota			reply = dbus_message_new_error(
137048104Syokota				message, WPAS_ERROR_ADD_ERROR,
137148104Syokota				"Error adding blob.");
137248104Syokota			break;
137348104Syokota		}
137448104Syokota
137548104Syokota		/* Success */
137648104Syokota		if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
137748104Syokota			wpas_notify_blob_removed(wpa_s, blob->name);
137848104Syokota		wpa_config_set_blob(wpa_s->conf, blob);
137948104Syokota		wpas_notify_blob_added(wpa_s, blob->name);
138048104Syokota
138148104Syokota		wpa_dbus_dict_entry_clear(&entry);
138248104Syokota	}
138348104Syokota	wpa_dbus_dict_entry_clear(&entry);
138448104Syokota
138548104Syokota	return reply ? reply : wpas_dbus_new_success_reply(message);
138648104Syokota}
138748104Syokota
138848104Syokota
138948104Syokota/**
139048104Syokota * wpas_dbus_iface_remove_blob - Remove named binary blobs
139148104Syokota * @message: Pointer to incoming dbus message
139248104Syokota * @wpa_s: %wpa_supplicant data structure
139348104Syokota * Returns: A dbus message containing a UINT32 indicating success (1) or
139448104Syokota *          failure (0)
139548104Syokota *
139648104Syokota * Asks wpa_supplicant to remove one or more previously stored binary blobs.
139748104Syokota */
139848104SyokotaDBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
139948104Syokota					   struct wpa_supplicant *wpa_s)
140050446Syokota{
140150446Syokota	DBusMessageIter iter, array;
140242504Syokota	char *err_msg = NULL;
140348104Syokota
140448104Syokota	dbus_message_iter_init(message, &iter);
140548104Syokota
140648104Syokota	if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
140750792Syokota	    (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
140850792Syokota		return wpas_dbus_new_invalid_opts_error(message, NULL);
140948104Syokota
141048104Syokota	dbus_message_iter_recurse(&iter, &array);
141148104Syokota	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
141250792Syokota		const char *name;
141350792Syokota
141448104Syokota		dbus_message_iter_get_basic(&array, &name);
141548104Syokota		if (!os_strlen(name))
141648104Syokota			err_msg = "Invalid blob name.";
141748104Syokota
141848104Syokota		if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
141948104Syokota			err_msg = "Error removing blob.";
142048104Syokota		else
142148104Syokota			wpas_notify_blob_removed(wpa_s, name);
142250792Syokota		dbus_message_iter_next(&array);
142350792Syokota	}
142450446Syokota
142548104Syokota	if (err_msg)
142650446Syokota		return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
142750446Syokota					      err_msg);
142850446Syokota
142950446Syokota	return wpas_dbus_new_success_reply(message);
143048104Syokota}
143148104Syokota
143248104Syokota
143348104Syokota/**
143448104Syokota * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
143548104Syokota * @message: Pointer to incoming dbus message
143648104Syokota * @wpa_s: %wpa_supplicant data structure
143748104Syokota * Returns: a dbus message containing a UINT32 indicating success (1) or
143848104Syokota *          failure (0), or returns a dbus error message with more information
143948104Syokota *
144048104Syokota * Handler function for "flush" method call. Handles requests for an
144148104Syokota * interface with an optional "age" parameter that specifies the minimum
144248104Syokota * age of a BSS to be flushed.
144348104Syokota */
144448104SyokotaDBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
144548104Syokota				    struct wpa_supplicant *wpa_s)
144648104Syokota{
144748104Syokota	int flush_age = 0;
144848104Syokota
144948104Syokota	if (os_strlen(dbus_message_get_signature(message)) != 0 &&
145048104Syokota	    !dbus_message_get_args(message, NULL,
145148104Syokota				   DBUS_TYPE_INT32, &flush_age,
145248104Syokota				   DBUS_TYPE_INVALID)) {
145348104Syokota		return wpas_dbus_new_invalid_opts_error(message, NULL);
145448104Syokota	}
145548104Syokota
145648104Syokota	if (flush_age == 0)
145748104Syokota		wpa_bss_flush(wpa_s);
145848104Syokota	else
145948104Syokota		wpa_bss_flush_by_age(wpa_s, flush_age);
146048104Syokota
146148104Syokota	return wpas_dbus_new_success_reply(message);
146248104Syokota}
146348104Syokota