1214501Srpaulo/*
2214501Srpaulo * WPA Supplicant / dbus-based control interface
3214501Srpaulo * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4214501Srpaulo *
5252190Srpaulo * This software may be distributed under the terms of the BSD license.
6252190Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "includes.h"
10214501Srpaulo#include <dbus/dbus.h>
11214501Srpaulo
12214501Srpaulo#include "common.h"
13214501Srpaulo#include "eap_peer/eap_methods.h"
14214501Srpaulo#include "common/ieee802_11_defs.h"
15214501Srpaulo#include "eapol_supp/eapol_supp_sm.h"
16214501Srpaulo#include "rsn_supp/wpa.h"
17214501Srpaulo#include "../config.h"
18214501Srpaulo#include "../wpa_supplicant_i.h"
19214501Srpaulo#include "../driver_i.h"
20214501Srpaulo#include "../notify.h"
21214501Srpaulo#include "../wpas_glue.h"
22214501Srpaulo#include "../bss.h"
23214501Srpaulo#include "../scan.h"
24214501Srpaulo#include "dbus_old.h"
25214501Srpaulo#include "dbus_old_handlers.h"
26214501Srpaulo#include "dbus_dict_helpers.h"
27214501Srpaulo
28214501Srpauloextern int wpa_debug_level;
29214501Srpauloextern int wpa_debug_show_keys;
30214501Srpauloextern int wpa_debug_timestamp;
31214501Srpaulo
32214501Srpaulo/**
33214501Srpaulo * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
34214501Srpaulo * @message: Pointer to incoming dbus message this error refers to
35214501Srpaulo * Returns: a dbus error message
36214501Srpaulo *
37214501Srpaulo * Convenience function to create and return an invalid options error
38214501Srpaulo */
39214501SrpauloDBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
40214501Srpaulo					       const char *arg)
41214501Srpaulo{
42214501Srpaulo	DBusMessage *reply;
43214501Srpaulo
44214501Srpaulo	reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
45214501Srpaulo				       "Did not receive correct message "
46214501Srpaulo				       "arguments.");
47214501Srpaulo	if (arg != NULL)
48214501Srpaulo		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
49214501Srpaulo					 DBUS_TYPE_INVALID);
50214501Srpaulo
51214501Srpaulo	return reply;
52214501Srpaulo}
53214501Srpaulo
54214501Srpaulo
55214501Srpaulo/**
56214501Srpaulo * wpas_dbus_new_success_reply - Return a new success reply message
57214501Srpaulo * @message: Pointer to incoming dbus message this reply refers to
58214501Srpaulo * Returns: a dbus message containing a single UINT32 that indicates
59214501Srpaulo *          success (ie, a value of 1)
60214501Srpaulo *
61214501Srpaulo * Convenience function to create and return a success reply message
62214501Srpaulo */
63214501SrpauloDBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
64214501Srpaulo{
65214501Srpaulo	DBusMessage *reply;
66214501Srpaulo	unsigned int success = 1;
67214501Srpaulo
68214501Srpaulo	reply = dbus_message_new_method_return(message);
69214501Srpaulo	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
70214501Srpaulo				 DBUS_TYPE_INVALID);
71214501Srpaulo	return reply;
72214501Srpaulo}
73214501Srpaulo
74214501Srpaulo
75214501Srpaulo/**
76214501Srpaulo * wpas_dbus_global_add_interface - Request registration of a network interface
77214501Srpaulo * @message: Pointer to incoming dbus message
78214501Srpaulo * @global: %wpa_supplicant global data structure
79214501Srpaulo * Returns: The object path of the new interface object,
80214501Srpaulo *          or a dbus error message with more information
81214501Srpaulo *
82214501Srpaulo * Handler function for "addInterface" method call. Handles requests
83214501Srpaulo * by dbus clients to register a network interface that wpa_supplicant
84214501Srpaulo * will manage.
85214501Srpaulo */
86214501SrpauloDBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
87214501Srpaulo					     struct wpa_global *global)
88214501Srpaulo{
89214501Srpaulo	char *ifname = NULL;
90214501Srpaulo	char *driver = NULL;
91214501Srpaulo	char *driver_param = NULL;
92214501Srpaulo	char *confname = NULL;
93214501Srpaulo	char *bridge_ifname = NULL;
94214501Srpaulo	DBusMessage *reply = NULL;
95214501Srpaulo	DBusMessageIter iter;
96214501Srpaulo
97214501Srpaulo	dbus_message_iter_init(message, &iter);
98214501Srpaulo
99214501Srpaulo	/* First argument: interface name (DBUS_TYPE_STRING)
100214501Srpaulo	 *    Required; must be non-zero length
101214501Srpaulo	 */
102214501Srpaulo	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
103214501Srpaulo		goto error;
104214501Srpaulo	dbus_message_iter_get_basic(&iter, &ifname);
105214501Srpaulo	if (!os_strlen(ifname))
106214501Srpaulo		goto error;
107214501Srpaulo
108214501Srpaulo	/* Second argument: dict of options */
109214501Srpaulo	if (dbus_message_iter_next(&iter)) {
110214501Srpaulo		DBusMessageIter iter_dict;
111214501Srpaulo		struct wpa_dbus_dict_entry entry;
112214501Srpaulo
113252190Srpaulo		if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
114214501Srpaulo			goto error;
115214501Srpaulo		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
116214501Srpaulo			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
117214501Srpaulo				goto error;
118214501Srpaulo			if (!strcmp(entry.key, "driver") &&
119214501Srpaulo			    (entry.type == DBUS_TYPE_STRING)) {
120214501Srpaulo				driver = os_strdup(entry.str_value);
121214501Srpaulo				wpa_dbus_dict_entry_clear(&entry);
122214501Srpaulo				if (driver == NULL)
123214501Srpaulo					goto error;
124214501Srpaulo			} else if (!strcmp(entry.key, "driver-params") &&
125214501Srpaulo				   (entry.type == DBUS_TYPE_STRING)) {
126214501Srpaulo				driver_param = os_strdup(entry.str_value);
127214501Srpaulo				wpa_dbus_dict_entry_clear(&entry);
128214501Srpaulo				if (driver_param == NULL)
129214501Srpaulo					goto error;
130214501Srpaulo			} else if (!strcmp(entry.key, "config-file") &&
131214501Srpaulo				   (entry.type == DBUS_TYPE_STRING)) {
132214501Srpaulo				confname = os_strdup(entry.str_value);
133214501Srpaulo				wpa_dbus_dict_entry_clear(&entry);
134214501Srpaulo				if (confname == NULL)
135214501Srpaulo					goto error;
136214501Srpaulo			} else if (!strcmp(entry.key, "bridge-ifname") &&
137214501Srpaulo				   (entry.type == DBUS_TYPE_STRING)) {
138214501Srpaulo				bridge_ifname = os_strdup(entry.str_value);
139214501Srpaulo				wpa_dbus_dict_entry_clear(&entry);
140214501Srpaulo				if (bridge_ifname == NULL)
141214501Srpaulo					goto error;
142214501Srpaulo			} else {
143214501Srpaulo				wpa_dbus_dict_entry_clear(&entry);
144214501Srpaulo				goto error;
145214501Srpaulo			}
146214501Srpaulo		}
147214501Srpaulo	}
148214501Srpaulo
149214501Srpaulo	/*
150214501Srpaulo	 * Try to get the wpa_supplicant record for this iface, return
151214501Srpaulo	 * an error if we already control it.
152214501Srpaulo	 */
153214501Srpaulo	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
154214501Srpaulo		reply = dbus_message_new_error(message,
155214501Srpaulo					       WPAS_ERROR_EXISTS_ERROR,
156214501Srpaulo					       "wpa_supplicant already "
157214501Srpaulo					       "controls this interface.");
158214501Srpaulo	} else {
159214501Srpaulo		struct wpa_supplicant *wpa_s;
160214501Srpaulo		struct wpa_interface iface;
161214501Srpaulo		os_memset(&iface, 0, sizeof(iface));
162214501Srpaulo		iface.ifname = ifname;
163214501Srpaulo		iface.driver = driver;
164214501Srpaulo		iface.driver_param = driver_param;
165214501Srpaulo		iface.confname = confname;
166214501Srpaulo		iface.bridge_ifname = bridge_ifname;
167214501Srpaulo		/* Otherwise, have wpa_supplicant attach to it. */
168214501Srpaulo		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
169214501Srpaulo			const char *path = wpa_s->dbus_path;
170214501Srpaulo			reply = dbus_message_new_method_return(message);
171214501Srpaulo			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
172214501Srpaulo			                         &path, DBUS_TYPE_INVALID);
173214501Srpaulo		} else {
174214501Srpaulo			reply = dbus_message_new_error(message,
175214501Srpaulo						       WPAS_ERROR_ADD_ERROR,
176214501Srpaulo						       "wpa_supplicant "
177214501Srpaulo						       "couldn't grab this "
178214501Srpaulo						       "interface.");
179214501Srpaulo		}
180214501Srpaulo	}
181214501Srpaulo
182214501Srpauloout:
183214501Srpaulo	os_free(driver);
184214501Srpaulo	os_free(driver_param);
185214501Srpaulo	os_free(confname);
186214501Srpaulo	os_free(bridge_ifname);
187214501Srpaulo	return reply;
188214501Srpaulo
189214501Srpauloerror:
190214501Srpaulo	reply = wpas_dbus_new_invalid_opts_error(message, NULL);
191214501Srpaulo	goto out;
192214501Srpaulo}
193214501Srpaulo
194214501Srpaulo
195214501Srpaulo/**
196214501Srpaulo * wpas_dbus_global_remove_interface - Request deregistration of an interface
197214501Srpaulo * @message: Pointer to incoming dbus message
198214501Srpaulo * @global: wpa_supplicant global data structure
199214501Srpaulo * Returns: a dbus message containing a UINT32 indicating success (1) or
200214501Srpaulo *          failure (0), or returns a dbus error message with more information
201214501Srpaulo *
202214501Srpaulo * Handler function for "removeInterface" method call.  Handles requests
203214501Srpaulo * by dbus clients to deregister a network interface that wpa_supplicant
204214501Srpaulo * currently manages.
205214501Srpaulo */
206214501SrpauloDBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
207214501Srpaulo						struct wpa_global *global)
208214501Srpaulo{
209214501Srpaulo	struct wpa_supplicant *wpa_s;
210214501Srpaulo	char *path;
211214501Srpaulo	DBusMessage *reply = NULL;
212214501Srpaulo
213214501Srpaulo	if (!dbus_message_get_args(message, NULL,
214214501Srpaulo				   DBUS_TYPE_OBJECT_PATH, &path,
215214501Srpaulo				   DBUS_TYPE_INVALID)) {
216214501Srpaulo		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
217214501Srpaulo		goto out;
218214501Srpaulo	}
219214501Srpaulo
220214501Srpaulo	wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
221214501Srpaulo	if (wpa_s == NULL) {
222214501Srpaulo		reply = wpas_dbus_new_invalid_iface_error(message);
223214501Srpaulo		goto out;
224214501Srpaulo	}
225214501Srpaulo
226252190Srpaulo	if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
227214501Srpaulo		reply = wpas_dbus_new_success_reply(message);
228214501Srpaulo	} else {
229214501Srpaulo		reply = dbus_message_new_error(message,
230214501Srpaulo					       WPAS_ERROR_REMOVE_ERROR,
231214501Srpaulo					       "wpa_supplicant couldn't "
232214501Srpaulo					       "remove this interface.");
233214501Srpaulo	}
234214501Srpaulo
235214501Srpauloout:
236214501Srpaulo	return reply;
237214501Srpaulo}
238214501Srpaulo
239214501Srpaulo
240214501Srpaulo/**
241214501Srpaulo * wpas_dbus_global_get_interface - Get the object path for an interface name
242214501Srpaulo * @message: Pointer to incoming dbus message
243214501Srpaulo * @global: %wpa_supplicant global data structure
244214501Srpaulo * Returns: The object path of the interface object,
245214501Srpaulo *          or a dbus error message with more information
246214501Srpaulo *
247214501Srpaulo * Handler function for "getInterface" method call. Handles requests
248214501Srpaulo * by dbus clients for the object path of an specific network interface.
249214501Srpaulo */
250214501SrpauloDBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
251214501Srpaulo					     struct wpa_global *global)
252214501Srpaulo{
253214501Srpaulo	DBusMessage *reply = NULL;
254214501Srpaulo	const char *ifname;
255214501Srpaulo	const char *path;
256214501Srpaulo	struct wpa_supplicant *wpa_s;
257214501Srpaulo
258214501Srpaulo	if (!dbus_message_get_args(message, NULL,
259214501Srpaulo	                           DBUS_TYPE_STRING, &ifname,
260214501Srpaulo	                           DBUS_TYPE_INVALID)) {
261214501Srpaulo		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
262214501Srpaulo		goto out;
263214501Srpaulo	}
264214501Srpaulo
265214501Srpaulo	wpa_s = wpa_supplicant_get_iface(global, ifname);
266214501Srpaulo	if (wpa_s == NULL) {
267214501Srpaulo		reply = wpas_dbus_new_invalid_iface_error(message);
268214501Srpaulo		goto out;
269214501Srpaulo	}
270214501Srpaulo
271214501Srpaulo	path = wpa_s->dbus_path;
272214501Srpaulo	reply = dbus_message_new_method_return(message);
273214501Srpaulo	dbus_message_append_args(reply,
274214501Srpaulo	                         DBUS_TYPE_OBJECT_PATH, &path,
275214501Srpaulo	                         DBUS_TYPE_INVALID);
276214501Srpaulo
277214501Srpauloout:
278214501Srpaulo	return reply;
279214501Srpaulo}
280214501Srpaulo
281214501Srpaulo
282214501Srpaulo/**
283214501Srpaulo * wpas_dbus_global_set_debugparams- Set the debug params
284214501Srpaulo * @message: Pointer to incoming dbus message
285214501Srpaulo * @global: %wpa_supplicant global data structure
286214501Srpaulo * Returns: a dbus message containing a UINT32 indicating success (1) or
287214501Srpaulo *          failure (0), or returns a dbus error message with more information
288214501Srpaulo *
289214501Srpaulo * Handler function for "setDebugParams" method call. Handles requests
290214501Srpaulo * by dbus clients for the object path of an specific network interface.
291214501Srpaulo */
292214501SrpauloDBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
293214501Srpaulo					       struct wpa_global *global)
294214501Srpaulo{
295214501Srpaulo	DBusMessage *reply = NULL;
296214501Srpaulo	int debug_level;
297214501Srpaulo	dbus_bool_t debug_timestamp;
298214501Srpaulo	dbus_bool_t debug_show_keys;
299214501Srpaulo
300214501Srpaulo	if (!dbus_message_get_args(message, NULL,
301214501Srpaulo	                           DBUS_TYPE_INT32, &debug_level,
302214501Srpaulo	                           DBUS_TYPE_BOOLEAN, &debug_timestamp,
303214501Srpaulo	                           DBUS_TYPE_BOOLEAN, &debug_show_keys,
304214501Srpaulo	                           DBUS_TYPE_INVALID)) {
305214501Srpaulo		return wpas_dbus_new_invalid_opts_error(message, NULL);
306214501Srpaulo	}
307214501Srpaulo
308214501Srpaulo	if (wpa_supplicant_set_debug_params(global, debug_level,
309214501Srpaulo					    debug_timestamp ? 1 : 0,
310214501Srpaulo					    debug_show_keys ? 1 : 0)) {
311214501Srpaulo		return wpas_dbus_new_invalid_opts_error(message, NULL);
312214501Srpaulo	}
313214501Srpaulo
314214501Srpaulo	reply = wpas_dbus_new_success_reply(message);
315214501Srpaulo
316214501Srpaulo	return reply;
317214501Srpaulo}
318214501Srpaulo
319214501Srpaulo
320214501Srpaulo/**
321214501Srpaulo * wpas_dbus_iface_scan - Request a wireless scan on an interface
322214501Srpaulo * @message: Pointer to incoming dbus message
323214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
324214501Srpaulo * Returns: a dbus message containing a UINT32 indicating success (1) or
325214501Srpaulo *          failure (0)
326214501Srpaulo *
327214501Srpaulo * Handler function for "scan" method call of a network device. Requests
328214501Srpaulo * that wpa_supplicant perform a wireless scan as soon as possible
329214501Srpaulo * on a particular wireless interface.
330214501Srpaulo */
331214501SrpauloDBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
332214501Srpaulo				   struct wpa_supplicant *wpa_s)
333214501Srpaulo{
334252190Srpaulo	wpa_s->scan_req = MANUAL_SCAN_REQ;
335214501Srpaulo	wpa_supplicant_req_scan(wpa_s, 0, 0);
336214501Srpaulo	return wpas_dbus_new_success_reply(message);
337214501Srpaulo}
338214501Srpaulo
339214501Srpaulo
340214501Srpaulo/**
341214501Srpaulo * wpas_dbus_iface_scan_results - Get the results of a recent scan request
342214501Srpaulo * @message: Pointer to incoming dbus message
343214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
344214501Srpaulo * Returns: a dbus message containing a dbus array of objects paths, or returns
345214501Srpaulo *          a dbus error message if not scan results could be found
346214501Srpaulo *
347214501Srpaulo * Handler function for "scanResults" method call of a network device. Returns
348214501Srpaulo * a dbus message containing the object paths of wireless networks found.
349214501Srpaulo */
350214501SrpauloDBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
351214501Srpaulo					   struct wpa_supplicant *wpa_s)
352214501Srpaulo{
353214501Srpaulo	DBusMessage *reply = NULL;
354214501Srpaulo	DBusMessageIter iter;
355214501Srpaulo	DBusMessageIter sub_iter;
356214501Srpaulo	struct wpa_bss *bss;
357214501Srpaulo
358214501Srpaulo	/* Create and initialize the return message */
359214501Srpaulo	reply = dbus_message_new_method_return(message);
360214501Srpaulo	dbus_message_iter_init_append(reply, &iter);
361214501Srpaulo	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
362214501Srpaulo					 DBUS_TYPE_OBJECT_PATH_AS_STRING,
363214501Srpaulo					 &sub_iter);
364214501Srpaulo
365214501Srpaulo	/* Loop through scan results and append each result's object path */
366214501Srpaulo	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
367214501Srpaulo		char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
368214501Srpaulo		char *path = path_buf;
369214501Srpaulo
370214501Srpaulo		/* Construct the object path for this network.  Note that ':'
371214501Srpaulo		 * is not a valid character in dbus object paths.
372214501Srpaulo		 */
373214501Srpaulo		os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
374214501Srpaulo			    "%s/" WPAS_DBUS_BSSIDS_PART "/"
375214501Srpaulo			    WPAS_DBUS_BSSID_FORMAT,
376214501Srpaulo			    wpa_s->dbus_path, MAC2STR(bss->bssid));
377214501Srpaulo		dbus_message_iter_append_basic(&sub_iter,
378214501Srpaulo					       DBUS_TYPE_OBJECT_PATH, &path);
379214501Srpaulo	}
380214501Srpaulo
381214501Srpaulo	dbus_message_iter_close_container(&iter, &sub_iter);
382214501Srpaulo
383214501Srpaulo	return reply;
384214501Srpaulo}
385214501Srpaulo
386214501Srpaulo
387214501Srpaulo/**
388214501Srpaulo * wpas_dbus_bssid_properties - Return the properties of a scanned network
389214501Srpaulo * @message: Pointer to incoming dbus message
390214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
391214501Srpaulo * @res: wpa_supplicant scan result for which to get properties
392214501Srpaulo * Returns: a dbus message containing the properties for the requested network
393214501Srpaulo *
394214501Srpaulo * Handler function for "properties" method call of a scanned network.
395214501Srpaulo * Returns a dbus message containing the the properties.
396214501Srpaulo */
397214501SrpauloDBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
398214501Srpaulo					 struct wpa_supplicant *wpa_s,
399214501Srpaulo					 struct wpa_bss *bss)
400214501Srpaulo{
401214501Srpaulo	DBusMessage *reply;
402214501Srpaulo	DBusMessageIter iter, iter_dict;
403214501Srpaulo	const u8 *ie;
404214501Srpaulo
405214501Srpaulo	/* Dump the properties into a dbus message */
406214501Srpaulo	reply = dbus_message_new_method_return(message);
407214501Srpaulo
408214501Srpaulo	dbus_message_iter_init_append(reply, &iter);
409214501Srpaulo	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
410214501Srpaulo		goto error;
411214501Srpaulo
412214501Srpaulo	if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
413214501Srpaulo					     (const char *) bss->bssid,
414214501Srpaulo					     ETH_ALEN))
415214501Srpaulo		goto error;
416214501Srpaulo
417214501Srpaulo	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
418214501Srpaulo	if (ie) {
419214501Srpaulo		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
420214501Srpaulo						     (const char *) (ie + 2),
421214501Srpaulo						     ie[1]))
422214501Srpaulo		goto error;
423214501Srpaulo	}
424214501Srpaulo
425214501Srpaulo	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
426214501Srpaulo	if (ie) {
427214501Srpaulo		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
428214501Srpaulo						     (const char *) ie,
429214501Srpaulo						     ie[1] + 2))
430214501Srpaulo			goto error;
431214501Srpaulo	}
432214501Srpaulo
433214501Srpaulo	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
434214501Srpaulo	if (ie) {
435214501Srpaulo		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
436214501Srpaulo						     (const char *) ie,
437214501Srpaulo						     ie[1] + 2))
438214501Srpaulo			goto error;
439214501Srpaulo	}
440214501Srpaulo
441214501Srpaulo	ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
442214501Srpaulo	if (ie) {
443214501Srpaulo		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
444214501Srpaulo						     (const char *) ie,
445214501Srpaulo						     ie[1] + 2))
446214501Srpaulo			goto error;
447214501Srpaulo	}
448214501Srpaulo
449214501Srpaulo	if (bss->freq) {
450214501Srpaulo		if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
451214501Srpaulo						bss->freq))
452214501Srpaulo			goto error;
453214501Srpaulo	}
454214501Srpaulo	if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
455214501Srpaulo					 bss->caps))
456214501Srpaulo		goto error;
457214501Srpaulo	if (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
458214501Srpaulo	    !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual))
459214501Srpaulo		goto error;
460214501Srpaulo	if (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
461214501Srpaulo	    !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise))
462214501Srpaulo		goto error;
463214501Srpaulo	if (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
464214501Srpaulo	    !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level))
465214501Srpaulo		goto error;
466214501Srpaulo	if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
467214501Srpaulo					wpa_bss_get_max_rate(bss) * 500000))
468214501Srpaulo		goto error;
469214501Srpaulo
470214501Srpaulo	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
471214501Srpaulo		goto error;
472214501Srpaulo
473214501Srpaulo	return reply;
474214501Srpaulo
475214501Srpauloerror:
476214501Srpaulo	if (reply)
477214501Srpaulo		dbus_message_unref(reply);
478214501Srpaulo	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
479214501Srpaulo				      "an internal error occurred returning "
480214501Srpaulo				      "BSSID properties.");
481214501Srpaulo}
482214501Srpaulo
483214501Srpaulo
484214501Srpaulo/**
485214501Srpaulo * wpas_dbus_iface_capabilities - Return interface capabilities
486214501Srpaulo * @message: Pointer to incoming dbus message
487214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
488214501Srpaulo * Returns: A dbus message containing a dict of strings
489214501Srpaulo *
490214501Srpaulo * Handler function for "capabilities" method call of an interface.
491214501Srpaulo */
492214501SrpauloDBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
493214501Srpaulo					   struct wpa_supplicant *wpa_s)
494214501Srpaulo{
495214501Srpaulo	DBusMessage *reply = NULL;
496214501Srpaulo	struct wpa_driver_capa capa;
497214501Srpaulo	int res;
498214501Srpaulo	DBusMessageIter iter, iter_dict;
499214501Srpaulo	char **eap_methods;
500214501Srpaulo	size_t num_items;
501214501Srpaulo	dbus_bool_t strict = FALSE;
502214501Srpaulo	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
503214501Srpaulo
504214501Srpaulo	if (!dbus_message_get_args(message, NULL,
505214501Srpaulo				   DBUS_TYPE_BOOLEAN, &strict,
506214501Srpaulo				   DBUS_TYPE_INVALID))
507214501Srpaulo		strict = FALSE;
508214501Srpaulo
509214501Srpaulo	reply = dbus_message_new_method_return(message);
510214501Srpaulo
511214501Srpaulo	dbus_message_iter_init_append(reply, &iter);
512214501Srpaulo	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
513214501Srpaulo		goto error;
514214501Srpaulo
515214501Srpaulo	/* EAP methods */
516214501Srpaulo	eap_methods = eap_get_names_as_string_array(&num_items);
517214501Srpaulo	if (eap_methods) {
518214501Srpaulo		dbus_bool_t success = FALSE;
519214501Srpaulo		size_t i = 0;
520214501Srpaulo
521214501Srpaulo		success = wpa_dbus_dict_append_string_array(
522214501Srpaulo			&iter_dict, "eap", (const char **) eap_methods,
523214501Srpaulo			num_items);
524214501Srpaulo
525214501Srpaulo		/* free returned method array */
526214501Srpaulo		while (eap_methods[i])
527214501Srpaulo			os_free(eap_methods[i++]);
528214501Srpaulo		os_free(eap_methods);
529214501Srpaulo
530214501Srpaulo		if (!success)
531214501Srpaulo			goto error;
532214501Srpaulo	}
533214501Srpaulo
534214501Srpaulo	res = wpa_drv_get_capa(wpa_s, &capa);
535214501Srpaulo
536214501Srpaulo	/***** pairwise cipher */
537214501Srpaulo	if (res < 0) {
538214501Srpaulo		if (!strict) {
539214501Srpaulo			const char *args[] = {"CCMP", "TKIP", "NONE"};
540214501Srpaulo			if (!wpa_dbus_dict_append_string_array(
541214501Srpaulo				    &iter_dict, "pairwise", args,
542214501Srpaulo				    sizeof(args) / sizeof(char*)))
543214501Srpaulo				goto error;
544214501Srpaulo		}
545214501Srpaulo	} else {
546214501Srpaulo		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
547214501Srpaulo						      &iter_dict_entry,
548214501Srpaulo						      &iter_dict_val,
549214501Srpaulo						      &iter_array))
550214501Srpaulo			goto error;
551214501Srpaulo
552214501Srpaulo		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
553214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
554214501Srpaulo				    &iter_array, "CCMP"))
555214501Srpaulo				goto error;
556214501Srpaulo		}
557214501Srpaulo
558214501Srpaulo		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
559214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
560214501Srpaulo				    &iter_array, "TKIP"))
561214501Srpaulo				goto error;
562214501Srpaulo		}
563214501Srpaulo
564214501Srpaulo		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
565214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
566214501Srpaulo				    &iter_array, "NONE"))
567214501Srpaulo				goto error;
568214501Srpaulo		}
569214501Srpaulo
570214501Srpaulo		if (!wpa_dbus_dict_end_string_array(&iter_dict,
571214501Srpaulo						    &iter_dict_entry,
572214501Srpaulo						    &iter_dict_val,
573214501Srpaulo						    &iter_array))
574214501Srpaulo			goto error;
575214501Srpaulo	}
576214501Srpaulo
577214501Srpaulo	/***** group cipher */
578214501Srpaulo	if (res < 0) {
579214501Srpaulo		if (!strict) {
580214501Srpaulo			const char *args[] = {
581214501Srpaulo				"CCMP", "TKIP", "WEP104", "WEP40"
582214501Srpaulo			};
583214501Srpaulo			if (!wpa_dbus_dict_append_string_array(
584214501Srpaulo				    &iter_dict, "group", args,
585214501Srpaulo				    sizeof(args) / sizeof(char*)))
586214501Srpaulo				goto error;
587214501Srpaulo		}
588214501Srpaulo	} else {
589214501Srpaulo		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
590214501Srpaulo						      &iter_dict_entry,
591214501Srpaulo						      &iter_dict_val,
592214501Srpaulo						      &iter_array))
593214501Srpaulo			goto error;
594214501Srpaulo
595214501Srpaulo		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
596214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
597214501Srpaulo				    &iter_array, "CCMP"))
598214501Srpaulo				goto error;
599214501Srpaulo		}
600214501Srpaulo
601214501Srpaulo		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
602214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
603214501Srpaulo				    &iter_array, "TKIP"))
604214501Srpaulo				goto error;
605214501Srpaulo		}
606214501Srpaulo
607214501Srpaulo		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
608214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
609214501Srpaulo				    &iter_array, "WEP104"))
610214501Srpaulo				goto error;
611214501Srpaulo		}
612214501Srpaulo
613214501Srpaulo		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
614214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
615214501Srpaulo				    &iter_array, "WEP40"))
616214501Srpaulo				goto error;
617214501Srpaulo		}
618214501Srpaulo
619214501Srpaulo		if (!wpa_dbus_dict_end_string_array(&iter_dict,
620214501Srpaulo						    &iter_dict_entry,
621214501Srpaulo						    &iter_dict_val,
622214501Srpaulo						    &iter_array))
623214501Srpaulo			goto error;
624214501Srpaulo	}
625214501Srpaulo
626214501Srpaulo	/***** key management */
627214501Srpaulo	if (res < 0) {
628214501Srpaulo		if (!strict) {
629214501Srpaulo			const char *args[] = {
630214501Srpaulo				"WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
631214501Srpaulo				"NONE"
632214501Srpaulo			};
633214501Srpaulo			if (!wpa_dbus_dict_append_string_array(
634214501Srpaulo				    &iter_dict, "key_mgmt", args,
635214501Srpaulo				    sizeof(args) / sizeof(char*)))
636214501Srpaulo				goto error;
637214501Srpaulo		}
638214501Srpaulo	} else {
639214501Srpaulo		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
640214501Srpaulo						      &iter_dict_entry,
641214501Srpaulo						      &iter_dict_val,
642214501Srpaulo						      &iter_array))
643214501Srpaulo			goto error;
644214501Srpaulo
645214501Srpaulo		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
646214501Srpaulo							    "NONE"))
647214501Srpaulo			goto error;
648214501Srpaulo
649214501Srpaulo		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
650214501Srpaulo							    "IEEE8021X"))
651214501Srpaulo			goto error;
652214501Srpaulo
653214501Srpaulo		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
654214501Srpaulo				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
655214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
656214501Srpaulo				    &iter_array, "WPA-EAP"))
657214501Srpaulo				goto error;
658214501Srpaulo		}
659214501Srpaulo
660214501Srpaulo		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
661214501Srpaulo				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
662214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
663214501Srpaulo				    &iter_array, "WPA-PSK"))
664214501Srpaulo				goto error;
665214501Srpaulo		}
666214501Srpaulo
667214501Srpaulo		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
668214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
669214501Srpaulo				    &iter_array, "WPA-NONE"))
670214501Srpaulo				goto error;
671214501Srpaulo		}
672214501Srpaulo
673214501Srpaulo		if (!wpa_dbus_dict_end_string_array(&iter_dict,
674214501Srpaulo						    &iter_dict_entry,
675214501Srpaulo						    &iter_dict_val,
676214501Srpaulo						    &iter_array))
677214501Srpaulo			goto error;
678214501Srpaulo	}
679214501Srpaulo
680214501Srpaulo	/***** WPA protocol */
681214501Srpaulo	if (res < 0) {
682214501Srpaulo		if (!strict) {
683214501Srpaulo			const char *args[] = { "RSN", "WPA" };
684214501Srpaulo			if (!wpa_dbus_dict_append_string_array(
685214501Srpaulo				    &iter_dict, "proto", args,
686214501Srpaulo				    sizeof(args) / sizeof(char*)))
687214501Srpaulo				goto error;
688214501Srpaulo		}
689214501Srpaulo	} else {
690214501Srpaulo		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
691214501Srpaulo						      &iter_dict_entry,
692214501Srpaulo						      &iter_dict_val,
693214501Srpaulo						      &iter_array))
694214501Srpaulo			goto error;
695214501Srpaulo
696214501Srpaulo		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
697214501Srpaulo				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
698214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
699214501Srpaulo				    &iter_array, "RSN"))
700214501Srpaulo				goto error;
701214501Srpaulo		}
702214501Srpaulo
703214501Srpaulo		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
704214501Srpaulo				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
705214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
706214501Srpaulo				    &iter_array, "WPA"))
707214501Srpaulo				goto error;
708214501Srpaulo		}
709214501Srpaulo
710214501Srpaulo		if (!wpa_dbus_dict_end_string_array(&iter_dict,
711214501Srpaulo						    &iter_dict_entry,
712214501Srpaulo						    &iter_dict_val,
713214501Srpaulo						    &iter_array))
714214501Srpaulo			goto error;
715214501Srpaulo	}
716214501Srpaulo
717214501Srpaulo	/***** auth alg */
718214501Srpaulo	if (res < 0) {
719214501Srpaulo		if (!strict) {
720214501Srpaulo			const char *args[] = { "OPEN", "SHARED", "LEAP" };
721214501Srpaulo			if (!wpa_dbus_dict_append_string_array(
722214501Srpaulo				    &iter_dict, "auth_alg", args,
723214501Srpaulo				    sizeof(args) / sizeof(char*)))
724214501Srpaulo				goto error;
725214501Srpaulo		}
726214501Srpaulo	} else {
727214501Srpaulo		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
728214501Srpaulo						      &iter_dict_entry,
729214501Srpaulo						      &iter_dict_val,
730214501Srpaulo						      &iter_array))
731214501Srpaulo			goto error;
732214501Srpaulo
733214501Srpaulo		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
734214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
735214501Srpaulo				    &iter_array, "OPEN"))
736214501Srpaulo				goto error;
737214501Srpaulo		}
738214501Srpaulo
739214501Srpaulo		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
740214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
741214501Srpaulo				    &iter_array, "SHARED"))
742214501Srpaulo				goto error;
743214501Srpaulo		}
744214501Srpaulo
745214501Srpaulo		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
746214501Srpaulo			if (!wpa_dbus_dict_string_array_add_element(
747214501Srpaulo				    &iter_array, "LEAP"))
748214501Srpaulo				goto error;
749214501Srpaulo		}
750214501Srpaulo
751214501Srpaulo		if (!wpa_dbus_dict_end_string_array(&iter_dict,
752214501Srpaulo						    &iter_dict_entry,
753214501Srpaulo						    &iter_dict_val,
754214501Srpaulo						    &iter_array))
755214501Srpaulo			goto error;
756214501Srpaulo	}
757214501Srpaulo
758214501Srpaulo	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
759214501Srpaulo		goto error;
760214501Srpaulo
761214501Srpaulo	return reply;
762214501Srpaulo
763214501Srpauloerror:
764214501Srpaulo	if (reply)
765214501Srpaulo		dbus_message_unref(reply);
766214501Srpaulo	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
767214501Srpaulo				      "an internal error occurred returning "
768214501Srpaulo				      "interface capabilities.");
769214501Srpaulo}
770214501Srpaulo
771214501Srpaulo
772214501Srpaulo/**
773214501Srpaulo * wpas_dbus_iface_add_network - Add a new configured network
774214501Srpaulo * @message: Pointer to incoming dbus message
775214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
776214501Srpaulo * Returns: A dbus message containing the object path of the new network
777214501Srpaulo *
778214501Srpaulo * Handler function for "addNetwork" method call of a network interface.
779214501Srpaulo */
780214501SrpauloDBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
781214501Srpaulo					  struct wpa_supplicant *wpa_s)
782214501Srpaulo{
783214501Srpaulo	DBusMessage *reply = NULL;
784214501Srpaulo	struct wpa_ssid *ssid;
785214501Srpaulo	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
786214501Srpaulo
787214501Srpaulo	ssid = wpa_config_add_network(wpa_s->conf);
788214501Srpaulo	if (ssid == NULL) {
789214501Srpaulo		reply = dbus_message_new_error(message,
790214501Srpaulo					       WPAS_ERROR_ADD_NETWORK_ERROR,
791214501Srpaulo					       "wpa_supplicant could not add "
792214501Srpaulo					       "a network on this interface.");
793214501Srpaulo		goto out;
794214501Srpaulo	}
795214501Srpaulo	wpas_notify_network_added(wpa_s, ssid);
796214501Srpaulo	ssid->disabled = 1;
797214501Srpaulo	wpa_config_set_network_defaults(ssid);
798214501Srpaulo
799214501Srpaulo	/* Construct the object path for this network. */
800214501Srpaulo	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
801214501Srpaulo		    "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
802214501Srpaulo		    wpa_s->dbus_path, ssid->id);
803214501Srpaulo
804214501Srpaulo	reply = dbus_message_new_method_return(message);
805214501Srpaulo	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
806214501Srpaulo				 &path, DBUS_TYPE_INVALID);
807214501Srpaulo
808214501Srpauloout:
809214501Srpaulo	return reply;
810214501Srpaulo}
811214501Srpaulo
812214501Srpaulo
813214501Srpaulo/**
814214501Srpaulo * wpas_dbus_iface_remove_network - Remove a configured network
815214501Srpaulo * @message: Pointer to incoming dbus message
816214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
817214501Srpaulo * Returns: A dbus message containing a UINT32 indicating success (1) or
818214501Srpaulo *          failure (0)
819214501Srpaulo *
820214501Srpaulo * Handler function for "removeNetwork" method call of a network interface.
821214501Srpaulo */
822214501SrpauloDBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
823214501Srpaulo					     struct wpa_supplicant *wpa_s)
824214501Srpaulo{
825214501Srpaulo	DBusMessage *reply = NULL;
826214501Srpaulo	const char *op;
827214501Srpaulo	char *iface = NULL, *net_id = NULL;
828214501Srpaulo	int id;
829214501Srpaulo	struct wpa_ssid *ssid;
830214501Srpaulo
831214501Srpaulo	if (!dbus_message_get_args(message, NULL,
832214501Srpaulo	                           DBUS_TYPE_OBJECT_PATH, &op,
833214501Srpaulo	                           DBUS_TYPE_INVALID)) {
834214501Srpaulo		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
835214501Srpaulo		goto out;
836214501Srpaulo	}
837214501Srpaulo
838214501Srpaulo	/* Extract the network ID */
839214501Srpaulo	iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
840214501Srpaulo	if (iface == NULL) {
841214501Srpaulo		reply = wpas_dbus_new_invalid_network_error(message);
842214501Srpaulo		goto out;
843214501Srpaulo	}
844214501Srpaulo
845214501Srpaulo	/* Ensure the network is actually a child of this interface */
846214501Srpaulo	if (os_strcmp(iface, wpa_s->dbus_path) != 0) {
847214501Srpaulo		reply = wpas_dbus_new_invalid_network_error(message);
848214501Srpaulo		goto out;
849214501Srpaulo	}
850214501Srpaulo
851214501Srpaulo	id = strtoul(net_id, NULL, 10);
852214501Srpaulo	ssid = wpa_config_get_network(wpa_s->conf, id);
853214501Srpaulo	if (ssid == NULL) {
854214501Srpaulo		reply = wpas_dbus_new_invalid_network_error(message);
855214501Srpaulo		goto out;
856214501Srpaulo	}
857214501Srpaulo
858214501Srpaulo	wpas_notify_network_removed(wpa_s, ssid);
859214501Srpaulo
860214501Srpaulo	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
861214501Srpaulo		reply = dbus_message_new_error(message,
862214501Srpaulo					       WPAS_ERROR_REMOVE_NETWORK_ERROR,
863214501Srpaulo					       "error removing the specified "
864214501Srpaulo					       "on this interface.");
865214501Srpaulo		goto out;
866214501Srpaulo	}
867214501Srpaulo
868214501Srpaulo	if (ssid == wpa_s->current_ssid)
869214501Srpaulo		wpa_supplicant_deauthenticate(wpa_s,
870214501Srpaulo					      WLAN_REASON_DEAUTH_LEAVING);
871214501Srpaulo	reply = wpas_dbus_new_success_reply(message);
872214501Srpaulo
873214501Srpauloout:
874214501Srpaulo	os_free(iface);
875214501Srpaulo	os_free(net_id);
876214501Srpaulo	return reply;
877214501Srpaulo}
878214501Srpaulo
879214501Srpaulo
880214501Srpaulostatic const char *dont_quote[] = {
881214501Srpaulo	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
882214501Srpaulo	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
883214501Srpaulo	"bssid", NULL
884214501Srpaulo};
885214501Srpaulo
886214501Srpaulo
887214501Srpaulostatic dbus_bool_t should_quote_opt(const char *key)
888214501Srpaulo{
889214501Srpaulo	int i = 0;
890214501Srpaulo	while (dont_quote[i] != NULL) {
891214501Srpaulo		if (strcmp(key, dont_quote[i]) == 0)
892214501Srpaulo			return FALSE;
893214501Srpaulo		i++;
894214501Srpaulo	}
895214501Srpaulo	return TRUE;
896214501Srpaulo}
897214501Srpaulo
898214501Srpaulo
899214501Srpaulo/**
900214501Srpaulo * wpas_dbus_iface_set_network - Set options for a configured network
901214501Srpaulo * @message: Pointer to incoming dbus message
902214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
903214501Srpaulo * @ssid: wpa_ssid structure for a configured network
904214501Srpaulo * Returns: a dbus message containing a UINT32 indicating success (1) or
905214501Srpaulo *          failure (0)
906214501Srpaulo *
907214501Srpaulo * Handler function for "set" method call of a configured network.
908214501Srpaulo */
909214501SrpauloDBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
910214501Srpaulo					  struct wpa_supplicant *wpa_s,
911214501Srpaulo					  struct wpa_ssid *ssid)
912214501Srpaulo{
913214501Srpaulo	DBusMessage *reply = NULL;
914214501Srpaulo	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
915214501Srpaulo	DBusMessageIter	iter, iter_dict;
916214501Srpaulo
917214501Srpaulo	dbus_message_iter_init(message, &iter);
918214501Srpaulo
919252190Srpaulo	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
920214501Srpaulo		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
921214501Srpaulo		goto out;
922214501Srpaulo	}
923214501Srpaulo
924214501Srpaulo	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
925214501Srpaulo		char *value = NULL;
926214501Srpaulo		size_t size = 50;
927214501Srpaulo		int ret;
928214501Srpaulo
929214501Srpaulo		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
930214501Srpaulo			reply = wpas_dbus_new_invalid_opts_error(message,
931214501Srpaulo								 NULL);
932214501Srpaulo			goto out;
933214501Srpaulo		}
934214501Srpaulo
935214501Srpaulo		/* Type conversions, since wpa_supplicant wants strings */
936214501Srpaulo		if (entry.type == DBUS_TYPE_ARRAY &&
937214501Srpaulo		    entry.array_type == DBUS_TYPE_BYTE) {
938214501Srpaulo			if (entry.array_len <= 0)
939214501Srpaulo				goto error;
940214501Srpaulo
941214501Srpaulo			size = entry.array_len * 2 + 1;
942214501Srpaulo			value = os_zalloc(size);
943214501Srpaulo			if (value == NULL)
944214501Srpaulo				goto error;
945214501Srpaulo			ret = wpa_snprintf_hex(value, size,
946214501Srpaulo					       (u8 *) entry.bytearray_value,
947214501Srpaulo					       entry.array_len);
948214501Srpaulo			if (ret <= 0)
949214501Srpaulo				goto error;
950214501Srpaulo		} else if (entry.type == DBUS_TYPE_STRING) {
951214501Srpaulo			if (should_quote_opt(entry.key)) {
952214501Srpaulo				size = os_strlen(entry.str_value);
953214501Srpaulo				/* Zero-length option check */
954214501Srpaulo				if (size <= 0)
955214501Srpaulo					goto error;
956214501Srpaulo				size += 3;  /* For quotes and terminator */
957214501Srpaulo				value = os_zalloc(size);
958214501Srpaulo				if (value == NULL)
959214501Srpaulo					goto error;
960214501Srpaulo				ret = os_snprintf(value, size, "\"%s\"",
961214501Srpaulo						  entry.str_value);
962214501Srpaulo				if (ret < 0 || (size_t) ret != (size - 1))
963214501Srpaulo					goto error;
964214501Srpaulo			} else {
965214501Srpaulo				value = os_strdup(entry.str_value);
966214501Srpaulo				if (value == NULL)
967214501Srpaulo					goto error;
968214501Srpaulo			}
969214501Srpaulo		} else if (entry.type == DBUS_TYPE_UINT32) {
970214501Srpaulo			value = os_zalloc(size);
971214501Srpaulo			if (value == NULL)
972214501Srpaulo				goto error;
973214501Srpaulo			ret = os_snprintf(value, size, "%u",
974214501Srpaulo					  entry.uint32_value);
975214501Srpaulo			if (ret <= 0)
976214501Srpaulo				goto error;
977214501Srpaulo		} else if (entry.type == DBUS_TYPE_INT32) {
978214501Srpaulo			value = os_zalloc(size);
979214501Srpaulo			if (value == NULL)
980214501Srpaulo				goto error;
981214501Srpaulo			ret = os_snprintf(value, size, "%d",
982214501Srpaulo					  entry.int32_value);
983214501Srpaulo			if (ret <= 0)
984214501Srpaulo				goto error;
985214501Srpaulo		} else
986214501Srpaulo			goto error;
987214501Srpaulo
988214501Srpaulo		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
989214501Srpaulo			goto error;
990214501Srpaulo
991214501Srpaulo		if ((os_strcmp(entry.key, "psk") == 0 &&
992214501Srpaulo		     value[0] == '"' && ssid->ssid_len) ||
993214501Srpaulo		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
994214501Srpaulo			wpa_config_update_psk(ssid);
995214501Srpaulo		else if (os_strcmp(entry.key, "priority") == 0)
996214501Srpaulo			wpa_config_update_prio_list(wpa_s->conf);
997214501Srpaulo
998214501Srpaulo		os_free(value);
999214501Srpaulo		wpa_dbus_dict_entry_clear(&entry);
1000214501Srpaulo		continue;
1001214501Srpaulo
1002214501Srpaulo	error:
1003214501Srpaulo		os_free(value);
1004214501Srpaulo		reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
1005214501Srpaulo		wpa_dbus_dict_entry_clear(&entry);
1006214501Srpaulo		break;
1007214501Srpaulo	}
1008214501Srpaulo
1009214501Srpaulo	if (!reply)
1010214501Srpaulo		reply = wpas_dbus_new_success_reply(message);
1011214501Srpaulo
1012214501Srpauloout:
1013214501Srpaulo	return reply;
1014214501Srpaulo}
1015214501Srpaulo
1016214501Srpaulo
1017214501Srpaulo/**
1018214501Srpaulo * wpas_dbus_iface_enable_network - Mark a configured network as enabled
1019214501Srpaulo * @message: Pointer to incoming dbus message
1020214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1021214501Srpaulo * @ssid: wpa_ssid structure for a configured network
1022214501Srpaulo * Returns: A dbus message containing a UINT32 indicating success (1) or
1023214501Srpaulo *          failure (0)
1024214501Srpaulo *
1025214501Srpaulo * Handler function for "enable" method call of a configured network.
1026214501Srpaulo */
1027214501SrpauloDBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
1028214501Srpaulo					     struct wpa_supplicant *wpa_s,
1029214501Srpaulo					     struct wpa_ssid *ssid)
1030214501Srpaulo{
1031214501Srpaulo	wpa_supplicant_enable_network(wpa_s, ssid);
1032214501Srpaulo	return wpas_dbus_new_success_reply(message);
1033214501Srpaulo}
1034214501Srpaulo
1035214501Srpaulo
1036214501Srpaulo/**
1037214501Srpaulo * wpas_dbus_iface_disable_network - Mark a configured network as disabled
1038214501Srpaulo * @message: Pointer to incoming dbus message
1039214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1040214501Srpaulo * @ssid: wpa_ssid structure for a configured network
1041214501Srpaulo * Returns: A dbus message containing a UINT32 indicating success (1) or
1042214501Srpaulo *          failure (0)
1043214501Srpaulo *
1044214501Srpaulo * Handler function for "disable" method call of a configured network.
1045214501Srpaulo */
1046214501SrpauloDBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
1047214501Srpaulo					      struct wpa_supplicant *wpa_s,
1048214501Srpaulo					      struct wpa_ssid *ssid)
1049214501Srpaulo{
1050214501Srpaulo	wpa_supplicant_disable_network(wpa_s, ssid);
1051214501Srpaulo	return wpas_dbus_new_success_reply(message);
1052214501Srpaulo}
1053214501Srpaulo
1054214501Srpaulo
1055214501Srpaulo/**
1056214501Srpaulo * wpas_dbus_iface_select_network - Attempt association with a configured network
1057214501Srpaulo * @message: Pointer to incoming dbus message
1058214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1059214501Srpaulo * Returns: A dbus message containing a UINT32 indicating success (1) or
1060214501Srpaulo *          failure (0)
1061214501Srpaulo *
1062214501Srpaulo * Handler function for "selectNetwork" method call of network interface.
1063214501Srpaulo */
1064214501SrpauloDBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
1065214501Srpaulo					     struct wpa_supplicant *wpa_s)
1066214501Srpaulo{
1067214501Srpaulo	DBusMessage *reply = NULL;
1068214501Srpaulo	const char *op;
1069214501Srpaulo	struct wpa_ssid *ssid;
1070214501Srpaulo	char *iface_obj_path = NULL;
1071214501Srpaulo	char *network = NULL;
1072214501Srpaulo
1073214501Srpaulo	if (os_strlen(dbus_message_get_signature(message)) == 0) {
1074214501Srpaulo		/* Any network */
1075214501Srpaulo		ssid = NULL;
1076214501Srpaulo	} else {
1077214501Srpaulo		int nid;
1078214501Srpaulo
1079214501Srpaulo		if (!dbus_message_get_args(message, NULL,
1080214501Srpaulo					   DBUS_TYPE_OBJECT_PATH, &op,
1081214501Srpaulo					   DBUS_TYPE_INVALID)) {
1082214501Srpaulo			reply = wpas_dbus_new_invalid_opts_error(message,
1083214501Srpaulo								 NULL);
1084214501Srpaulo			goto out;
1085214501Srpaulo		}
1086214501Srpaulo
1087214501Srpaulo		/* Extract the network number */
1088214501Srpaulo		iface_obj_path = wpas_dbus_decompose_object_path(op,
1089214501Srpaulo								 &network,
1090214501Srpaulo								 NULL);
1091214501Srpaulo		if (iface_obj_path == NULL) {
1092214501Srpaulo			reply = wpas_dbus_new_invalid_iface_error(message);
1093214501Srpaulo			goto out;
1094214501Srpaulo		}
1095214501Srpaulo		/* Ensure the object path really points to this interface */
1096214501Srpaulo		if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
1097214501Srpaulo			reply = wpas_dbus_new_invalid_network_error(message);
1098214501Srpaulo			goto out;
1099214501Srpaulo		}
1100214501Srpaulo
1101214501Srpaulo		nid = strtoul(network, NULL, 10);
1102214501Srpaulo		if (errno == EINVAL) {
1103214501Srpaulo			reply = wpas_dbus_new_invalid_network_error(message);
1104214501Srpaulo			goto out;
1105214501Srpaulo		}
1106214501Srpaulo
1107214501Srpaulo		ssid = wpa_config_get_network(wpa_s->conf, nid);
1108214501Srpaulo		if (ssid == NULL) {
1109214501Srpaulo			reply = wpas_dbus_new_invalid_network_error(message);
1110214501Srpaulo			goto out;
1111214501Srpaulo		}
1112214501Srpaulo	}
1113214501Srpaulo
1114214501Srpaulo	/* Finally, associate with the network */
1115214501Srpaulo	wpa_supplicant_select_network(wpa_s, ssid);
1116214501Srpaulo
1117214501Srpaulo	reply = wpas_dbus_new_success_reply(message);
1118214501Srpaulo
1119214501Srpauloout:
1120214501Srpaulo	os_free(iface_obj_path);
1121214501Srpaulo	os_free(network);
1122214501Srpaulo	return reply;
1123214501Srpaulo}
1124214501Srpaulo
1125214501Srpaulo
1126214501Srpaulo/**
1127214501Srpaulo * wpas_dbus_iface_disconnect - Terminate the current connection
1128214501Srpaulo * @message: Pointer to incoming dbus message
1129214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1130214501Srpaulo * Returns: A dbus message containing a UINT32 indicating success (1) or
1131214501Srpaulo *          failure (0)
1132214501Srpaulo *
1133214501Srpaulo * Handler function for "disconnect" method call of network interface.
1134214501Srpaulo */
1135214501SrpauloDBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
1136214501Srpaulo					 struct wpa_supplicant *wpa_s)
1137214501Srpaulo{
1138214501Srpaulo	wpa_s->disconnected = 1;
1139214501Srpaulo	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1140214501Srpaulo
1141214501Srpaulo	return wpas_dbus_new_success_reply(message);
1142214501Srpaulo}
1143214501Srpaulo
1144214501Srpaulo
1145214501Srpaulo/**
1146214501Srpaulo * wpas_dbus_iface_set_ap_scan - Control roaming mode
1147214501Srpaulo * @message: Pointer to incoming dbus message
1148214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1149214501Srpaulo * Returns: A dbus message containing a UINT32 indicating success (1) or
1150214501Srpaulo *          failure (0)
1151214501Srpaulo *
1152214501Srpaulo * Handler function for "setAPScan" method call.
1153214501Srpaulo */
1154214501SrpauloDBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
1155214501Srpaulo					  struct wpa_supplicant *wpa_s)
1156214501Srpaulo{
1157214501Srpaulo	DBusMessage *reply = NULL;
1158214501Srpaulo	dbus_uint32_t ap_scan = 1;
1159214501Srpaulo
1160214501Srpaulo	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
1161214501Srpaulo				   DBUS_TYPE_INVALID)) {
1162214501Srpaulo		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1163214501Srpaulo		goto out;
1164214501Srpaulo	}
1165214501Srpaulo
1166214501Srpaulo	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
1167214501Srpaulo		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1168214501Srpaulo		goto out;
1169214501Srpaulo	}
1170214501Srpaulo
1171214501Srpaulo	reply = wpas_dbus_new_success_reply(message);
1172214501Srpaulo
1173214501Srpauloout:
1174214501Srpaulo	return reply;
1175214501Srpaulo}
1176214501Srpaulo
1177214501Srpaulo
1178214501Srpaulo/**
1179214501Srpaulo * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
1180214501Srpaulo * @message: Pointer to incoming dbus message
1181214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1182214501Srpaulo * Returns: A dbus message containing a UINT32 indicating success (1) or
1183214501Srpaulo *          failure (0)
1184214501Srpaulo *
1185214501Srpaulo * Handler function for "setSmartcardModules" method call.
1186214501Srpaulo */
1187214501SrpauloDBusMessage * wpas_dbus_iface_set_smartcard_modules(
1188214501Srpaulo	DBusMessage *message, struct wpa_supplicant *wpa_s)
1189214501Srpaulo{
1190214501Srpaulo	DBusMessageIter iter, iter_dict;
1191214501Srpaulo	char *opensc_engine_path = NULL;
1192214501Srpaulo	char *pkcs11_engine_path = NULL;
1193214501Srpaulo	char *pkcs11_module_path = NULL;
1194214501Srpaulo	struct wpa_dbus_dict_entry entry;
1195214501Srpaulo
1196214501Srpaulo	if (!dbus_message_iter_init(message, &iter))
1197214501Srpaulo		goto error;
1198214501Srpaulo
1199252190Srpaulo	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1200214501Srpaulo		goto error;
1201214501Srpaulo
1202214501Srpaulo	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1203214501Srpaulo		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1204214501Srpaulo			goto error;
1205214501Srpaulo		if (!strcmp(entry.key, "opensc_engine_path") &&
1206214501Srpaulo		    (entry.type == DBUS_TYPE_STRING)) {
1207214501Srpaulo			opensc_engine_path = os_strdup(entry.str_value);
1208214501Srpaulo			if (opensc_engine_path == NULL)
1209214501Srpaulo				goto error;
1210214501Srpaulo		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
1211214501Srpaulo			   (entry.type == DBUS_TYPE_STRING)) {
1212214501Srpaulo			pkcs11_engine_path = os_strdup(entry.str_value);
1213214501Srpaulo			if (pkcs11_engine_path == NULL)
1214214501Srpaulo				goto error;
1215214501Srpaulo		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
1216214501Srpaulo				 (entry.type == DBUS_TYPE_STRING)) {
1217214501Srpaulo			pkcs11_module_path = os_strdup(entry.str_value);
1218214501Srpaulo			if (pkcs11_module_path == NULL)
1219214501Srpaulo				goto error;
1220214501Srpaulo		} else {
1221214501Srpaulo			wpa_dbus_dict_entry_clear(&entry);
1222214501Srpaulo			goto error;
1223214501Srpaulo		}
1224214501Srpaulo		wpa_dbus_dict_entry_clear(&entry);
1225214501Srpaulo	}
1226214501Srpaulo
1227214501Srpaulo	os_free(wpa_s->conf->opensc_engine_path);
1228214501Srpaulo	wpa_s->conf->opensc_engine_path = opensc_engine_path;
1229214501Srpaulo	os_free(wpa_s->conf->pkcs11_engine_path);
1230214501Srpaulo	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
1231214501Srpaulo	os_free(wpa_s->conf->pkcs11_module_path);
1232214501Srpaulo	wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
1233214501Srpaulo
1234214501Srpaulo	wpa_sm_set_eapol(wpa_s->wpa, NULL);
1235214501Srpaulo	eapol_sm_deinit(wpa_s->eapol);
1236214501Srpaulo	wpa_s->eapol = NULL;
1237214501Srpaulo	wpa_supplicant_init_eapol(wpa_s);
1238214501Srpaulo	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
1239214501Srpaulo
1240214501Srpaulo	return wpas_dbus_new_success_reply(message);
1241214501Srpaulo
1242214501Srpauloerror:
1243214501Srpaulo	os_free(opensc_engine_path);
1244214501Srpaulo	os_free(pkcs11_engine_path);
1245214501Srpaulo	os_free(pkcs11_module_path);
1246214501Srpaulo	return wpas_dbus_new_invalid_opts_error(message, NULL);
1247214501Srpaulo}
1248214501Srpaulo
1249214501Srpaulo
1250214501Srpaulo/**
1251214501Srpaulo * wpas_dbus_iface_get_state - Get interface state
1252214501Srpaulo * @message: Pointer to incoming dbus message
1253214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1254214501Srpaulo * Returns: A dbus message containing a STRING representing the current
1255214501Srpaulo *          interface state
1256214501Srpaulo *
1257214501Srpaulo * Handler function for "state" method call.
1258214501Srpaulo */
1259214501SrpauloDBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
1260214501Srpaulo					struct wpa_supplicant *wpa_s)
1261214501Srpaulo{
1262214501Srpaulo	DBusMessage *reply = NULL;
1263214501Srpaulo	const char *str_state;
1264214501Srpaulo
1265214501Srpaulo	reply = dbus_message_new_method_return(message);
1266214501Srpaulo	if (reply != NULL) {
1267214501Srpaulo		str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
1268214501Srpaulo		dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
1269214501Srpaulo					 DBUS_TYPE_INVALID);
1270214501Srpaulo	}
1271214501Srpaulo
1272214501Srpaulo	return reply;
1273214501Srpaulo}
1274214501Srpaulo
1275214501Srpaulo
1276214501Srpaulo/**
1277214501Srpaulo * wpas_dbus_iface_get_scanning - Get interface scanning state
1278214501Srpaulo * @message: Pointer to incoming dbus message
1279214501Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1280214501Srpaulo * Returns: A dbus message containing whether the interface is scanning
1281214501Srpaulo *
1282214501Srpaulo * Handler function for "scanning" method call.
1283214501Srpaulo */
1284214501SrpauloDBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
1285214501Srpaulo					   struct wpa_supplicant *wpa_s)
1286214501Srpaulo{
1287214501Srpaulo	DBusMessage *reply = NULL;
1288214501Srpaulo	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
1289214501Srpaulo
1290214501Srpaulo	reply = dbus_message_new_method_return(message);
1291214501Srpaulo	if (reply != NULL) {
1292214501Srpaulo		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
1293214501Srpaulo					 DBUS_TYPE_INVALID);
1294214501Srpaulo	} else {
1295214501Srpaulo		wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
1296214501Srpaulo			   "scanning state");
1297214501Srpaulo	}
1298214501Srpaulo
1299214501Srpaulo	return reply;
1300214501Srpaulo}
1301214501Srpaulo
1302214501Srpaulo
1303214501Srpaulo/**
1304214501Srpaulo * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
1305214501Srpaulo * @message: Pointer to incoming dbus message
1306214501Srpaulo * @wpa_s: %wpa_supplicant data structure
1307214501Srpaulo * Returns: A dbus message containing a UINT32 indicating success (1) or
1308214501Srpaulo *          failure (0)
1309214501Srpaulo *
1310214501Srpaulo * Asks wpa_supplicant to internally store a one or more binary blobs.
1311214501Srpaulo */
1312214501SrpauloDBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
1313214501Srpaulo					struct wpa_supplicant *wpa_s)
1314214501Srpaulo{
1315214501Srpaulo	DBusMessage *reply = NULL;
1316214501Srpaulo	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1317214501Srpaulo	DBusMessageIter	iter, iter_dict;
1318214501Srpaulo
1319214501Srpaulo	dbus_message_iter_init(message, &iter);
1320214501Srpaulo
1321252190Srpaulo	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1322214501Srpaulo		return wpas_dbus_new_invalid_opts_error(message, NULL);
1323214501Srpaulo
1324214501Srpaulo	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1325214501Srpaulo		struct wpa_config_blob *blob;
1326214501Srpaulo
1327214501Srpaulo		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1328214501Srpaulo			reply = wpas_dbus_new_invalid_opts_error(message,
1329214501Srpaulo								 NULL);
1330214501Srpaulo			break;
1331214501Srpaulo		}
1332214501Srpaulo
1333214501Srpaulo		if (entry.type != DBUS_TYPE_ARRAY ||
1334214501Srpaulo		    entry.array_type != DBUS_TYPE_BYTE) {
1335214501Srpaulo			reply = wpas_dbus_new_invalid_opts_error(
1336214501Srpaulo				message, "Byte array expected.");
1337214501Srpaulo			break;
1338214501Srpaulo		}
1339214501Srpaulo
1340214501Srpaulo		if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
1341214501Srpaulo		    !strlen(entry.key)) {
1342214501Srpaulo			reply = wpas_dbus_new_invalid_opts_error(
1343214501Srpaulo				message, "Invalid array size.");
1344214501Srpaulo			break;
1345214501Srpaulo		}
1346214501Srpaulo
1347214501Srpaulo		blob = os_zalloc(sizeof(*blob));
1348214501Srpaulo		if (blob == NULL) {
1349214501Srpaulo			reply = dbus_message_new_error(
1350214501Srpaulo				message, WPAS_ERROR_ADD_ERROR,
1351214501Srpaulo				"Not enough memory to add blob.");
1352214501Srpaulo			break;
1353214501Srpaulo		}
1354214501Srpaulo		blob->data = os_zalloc(entry.array_len);
1355214501Srpaulo		if (blob->data == NULL) {
1356214501Srpaulo			reply = dbus_message_new_error(
1357214501Srpaulo				message, WPAS_ERROR_ADD_ERROR,
1358214501Srpaulo				"Not enough memory to add blob data.");
1359214501Srpaulo			os_free(blob);
1360214501Srpaulo			break;
1361214501Srpaulo		}
1362214501Srpaulo
1363214501Srpaulo		blob->name = os_strdup(entry.key);
1364214501Srpaulo		blob->len = entry.array_len;
1365214501Srpaulo		os_memcpy(blob->data, (u8 *) entry.bytearray_value,
1366214501Srpaulo				entry.array_len);
1367214501Srpaulo		if (blob->name == NULL || blob->data == NULL) {
1368214501Srpaulo			wpa_config_free_blob(blob);
1369214501Srpaulo			reply = dbus_message_new_error(
1370214501Srpaulo				message, WPAS_ERROR_ADD_ERROR,
1371214501Srpaulo				"Error adding blob.");
1372214501Srpaulo			break;
1373214501Srpaulo		}
1374214501Srpaulo
1375214501Srpaulo		/* Success */
1376214501Srpaulo		if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
1377214501Srpaulo			wpas_notify_blob_removed(wpa_s, blob->name);
1378214501Srpaulo		wpa_config_set_blob(wpa_s->conf, blob);
1379214501Srpaulo		wpas_notify_blob_added(wpa_s, blob->name);
1380214501Srpaulo
1381214501Srpaulo		wpa_dbus_dict_entry_clear(&entry);
1382214501Srpaulo	}
1383214501Srpaulo	wpa_dbus_dict_entry_clear(&entry);
1384214501Srpaulo
1385214501Srpaulo	return reply ? reply : wpas_dbus_new_success_reply(message);
1386214501Srpaulo}
1387214501Srpaulo
1388214501Srpaulo
1389214501Srpaulo/**
1390214501Srpaulo * wpas_dbus_iface_remove_blob - Remove named binary blobs
1391214501Srpaulo * @message: Pointer to incoming dbus message
1392214501Srpaulo * @wpa_s: %wpa_supplicant data structure
1393214501Srpaulo * Returns: A dbus message containing a UINT32 indicating success (1) or
1394214501Srpaulo *          failure (0)
1395214501Srpaulo *
1396214501Srpaulo * Asks wpa_supplicant to remove one or more previously stored binary blobs.
1397214501Srpaulo */
1398214501SrpauloDBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
1399214501Srpaulo					   struct wpa_supplicant *wpa_s)
1400214501Srpaulo{
1401214501Srpaulo	DBusMessageIter iter, array;
1402214501Srpaulo	char *err_msg = NULL;
1403214501Srpaulo
1404214501Srpaulo	dbus_message_iter_init(message, &iter);
1405214501Srpaulo
1406214501Srpaulo	if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
1407214501Srpaulo	    (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
1408214501Srpaulo		return wpas_dbus_new_invalid_opts_error(message, NULL);
1409214501Srpaulo
1410214501Srpaulo	dbus_message_iter_recurse(&iter, &array);
1411214501Srpaulo	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
1412214501Srpaulo		const char *name;
1413214501Srpaulo
1414214501Srpaulo		dbus_message_iter_get_basic(&array, &name);
1415214501Srpaulo		if (!os_strlen(name))
1416214501Srpaulo			err_msg = "Invalid blob name.";
1417214501Srpaulo
1418214501Srpaulo		if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
1419214501Srpaulo			err_msg = "Error removing blob.";
1420214501Srpaulo		else
1421214501Srpaulo			wpas_notify_blob_removed(wpa_s, name);
1422214501Srpaulo		dbus_message_iter_next(&array);
1423214501Srpaulo	}
1424214501Srpaulo
1425214501Srpaulo	if (err_msg)
1426214501Srpaulo		return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
1427214501Srpaulo					      err_msg);
1428214501Srpaulo
1429214501Srpaulo	return wpas_dbus_new_success_reply(message);
1430214501Srpaulo}
1431252190Srpaulo
1432252190Srpaulo
1433252190Srpaulo/**
1434252190Srpaulo * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
1435252190Srpaulo * @message: Pointer to incoming dbus message
1436252190Srpaulo * @wpa_s: %wpa_supplicant data structure
1437252190Srpaulo * Returns: a dbus message containing a UINT32 indicating success (1) or
1438252190Srpaulo *          failure (0), or returns a dbus error message with more information
1439252190Srpaulo *
1440252190Srpaulo * Handler function for "flush" method call. Handles requests for an
1441252190Srpaulo * interface with an optional "age" parameter that specifies the minimum
1442252190Srpaulo * age of a BSS to be flushed.
1443252190Srpaulo */
1444252190SrpauloDBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
1445252190Srpaulo				    struct wpa_supplicant *wpa_s)
1446252190Srpaulo{
1447252190Srpaulo	int flush_age = 0;
1448252190Srpaulo
1449252190Srpaulo	if (os_strlen(dbus_message_get_signature(message)) != 0 &&
1450252190Srpaulo	    !dbus_message_get_args(message, NULL,
1451252190Srpaulo				   DBUS_TYPE_INT32, &flush_age,
1452252190Srpaulo				   DBUS_TYPE_INVALID)) {
1453252190Srpaulo		return wpas_dbus_new_invalid_opts_error(message, NULL);
1454252190Srpaulo	}
1455252190Srpaulo
1456252190Srpaulo	if (flush_age == 0)
1457252190Srpaulo		wpa_bss_flush(wpa_s);
1458252190Srpaulo	else
1459252190Srpaulo		wpa_bss_flush_by_age(wpa_s, flush_age);
1460252190Srpaulo
1461252190Srpaulo	return wpas_dbus_new_success_reply(message);
1462252190Srpaulo}
1463