dbus_old_handlers.c revision 203eadb9eda41a1dde4a583edb4684319e3f399e
1/*
2 * WPA Supplicant / dbus-based control interface
3 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10#include <dbus/dbus.h>
11
12#include "common.h"
13#include "eap_peer/eap_methods.h"
14#include "common/ieee802_11_defs.h"
15#include "eapol_supp/eapol_supp_sm.h"
16#include "rsn_supp/wpa.h"
17#include "../config.h"
18#include "../wpa_supplicant_i.h"
19#include "../driver_i.h"
20#include "../notify.h"
21#include "../wpas_glue.h"
22#include "../bss.h"
23#include "../scan.h"
24#include "dbus_old.h"
25#include "dbus_old_handlers.h"
26#include "dbus_dict_helpers.h"
27
28/**
29 * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
30 * @message: Pointer to incoming dbus message this error refers to
31 * Returns: a dbus error message
32 *
33 * Convenience function to create and return an invalid options error
34 */
35DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
36					       const char *arg)
37{
38	DBusMessage *reply;
39
40	reply = dbus_message_new_error(
41		message, WPAS_ERROR_INVALID_OPTS,
42		"Did not receive correct message arguments.");
43	if (arg != NULL)
44		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
45					 DBUS_TYPE_INVALID);
46
47	return reply;
48}
49
50
51/**
52 * wpas_dbus_new_success_reply - Return a new success reply message
53 * @message: Pointer to incoming dbus message this reply refers to
54 * Returns: a dbus message containing a single UINT32 that indicates
55 *          success (ie, a value of 1)
56 *
57 * Convenience function to create and return a success reply message
58 */
59DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
60{
61	DBusMessage *reply;
62	unsigned int success = 1;
63
64	reply = dbus_message_new_method_return(message);
65	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
66				 DBUS_TYPE_INVALID);
67	return reply;
68}
69
70
71/**
72 * wpas_dbus_global_add_interface - Request registration of a network interface
73 * @message: Pointer to incoming dbus message
74 * @global: %wpa_supplicant global data structure
75 * Returns: The object path of the new interface object,
76 *          or a dbus error message with more information
77 *
78 * Handler function for "addInterface" method call. Handles requests
79 * by dbus clients to register a network interface that wpa_supplicant
80 * will manage.
81 */
82DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
83					     struct wpa_global *global)
84{
85	char *ifname = NULL;
86	char *driver = NULL;
87	char *driver_param = NULL;
88	char *confname = NULL;
89	char *bridge_ifname = NULL;
90	DBusMessage *reply = NULL;
91	DBusMessageIter iter;
92
93	dbus_message_iter_init(message, &iter);
94
95	/* First argument: interface name (DBUS_TYPE_STRING)
96	 *    Required; must be non-zero length
97	 */
98	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
99		goto error;
100	dbus_message_iter_get_basic(&iter, &ifname);
101	if (!os_strlen(ifname))
102		goto error;
103
104	/* Second argument: dict of options */
105	if (dbus_message_iter_next(&iter)) {
106		DBusMessageIter iter_dict;
107		struct wpa_dbus_dict_entry entry;
108
109		if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
110			goto error;
111		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
112			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
113				goto error;
114			if (!strcmp(entry.key, "driver") &&
115			    entry.type == DBUS_TYPE_STRING) {
116				os_free(driver);
117				driver = os_strdup(entry.str_value);
118				wpa_dbus_dict_entry_clear(&entry);
119				if (driver == NULL)
120					goto error;
121			} else if (!strcmp(entry.key, "driver-params") &&
122				   entry.type == DBUS_TYPE_STRING) {
123				os_free(driver_param);
124				driver_param = os_strdup(entry.str_value);
125				wpa_dbus_dict_entry_clear(&entry);
126				if (driver_param == NULL)
127					goto error;
128			} else if (!strcmp(entry.key, "config-file") &&
129				   entry.type == DBUS_TYPE_STRING) {
130				os_free(confname);
131				confname = os_strdup(entry.str_value);
132				wpa_dbus_dict_entry_clear(&entry);
133				if (confname == NULL)
134					goto error;
135			} else if (!strcmp(entry.key, "bridge-ifname") &&
136				   entry.type == DBUS_TYPE_STRING) {
137				os_free(bridge_ifname);
138				bridge_ifname = os_strdup(entry.str_value);
139				wpa_dbus_dict_entry_clear(&entry);
140				if (bridge_ifname == NULL)
141					goto error;
142			} else {
143				wpa_dbus_dict_entry_clear(&entry);
144				goto error;
145			}
146		}
147	}
148
149	/*
150	 * Try to get the wpa_supplicant record for this iface, return
151	 * an error if we already control it.
152	 */
153	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
154		reply = dbus_message_new_error(
155			message, WPAS_ERROR_EXISTS_ERROR,
156			"wpa_supplicant already controls this interface.");
157	} else {
158		struct wpa_supplicant *wpa_s;
159		struct wpa_interface iface;
160
161		os_memset(&iface, 0, sizeof(iface));
162		iface.ifname = ifname;
163		iface.driver = driver;
164		iface.driver_param = driver_param;
165		iface.confname = confname;
166		iface.bridge_ifname = bridge_ifname;
167		/* Otherwise, have wpa_supplicant attach to it. */
168		wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
169		if (wpa_s) {
170			const char *path = wpa_s->dbus_path;
171
172			reply = dbus_message_new_method_return(message);
173			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
174						 &path, DBUS_TYPE_INVALID);
175		} else {
176			reply = dbus_message_new_error(
177				message, WPAS_ERROR_ADD_ERROR,
178				"wpa_supplicant couldn't grab this interface.");
179		}
180	}
181
182out:
183	os_free(driver);
184	os_free(driver_param);
185	os_free(confname);
186	os_free(bridge_ifname);
187	return reply;
188
189error:
190	reply = wpas_dbus_new_invalid_opts_error(message, NULL);
191	goto out;
192}
193
194
195/**
196 * wpas_dbus_global_remove_interface - Request deregistration of an interface
197 * @message: Pointer to incoming dbus message
198 * @global: wpa_supplicant global data structure
199 * Returns: a dbus message containing a UINT32 indicating success (1) or
200 *          failure (0), or returns a dbus error message with more information
201 *
202 * Handler function for "removeInterface" method call.  Handles requests
203 * by dbus clients to deregister a network interface that wpa_supplicant
204 * currently manages.
205 */
206DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
207						struct wpa_global *global)
208{
209	struct wpa_supplicant *wpa_s;
210	char *path;
211	DBusMessage *reply = NULL;
212
213	if (!dbus_message_get_args(message, NULL,
214				   DBUS_TYPE_OBJECT_PATH, &path,
215				   DBUS_TYPE_INVALID)) {
216		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
217		goto out;
218	}
219
220	wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
221	if (wpa_s == NULL) {
222		reply = wpas_dbus_new_invalid_iface_error(message);
223		goto out;
224	}
225
226	if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
227		reply = wpas_dbus_new_success_reply(message);
228	} else {
229		reply = dbus_message_new_error(
230			message, WPAS_ERROR_REMOVE_ERROR,
231			"wpa_supplicant couldn't remove this interface.");
232	}
233
234out:
235	return reply;
236}
237
238
239/**
240 * wpas_dbus_global_get_interface - Get the object path for an interface name
241 * @message: Pointer to incoming dbus message
242 * @global: %wpa_supplicant global data structure
243 * Returns: The object path of the interface object,
244 *          or a dbus error message with more information
245 *
246 * Handler function for "getInterface" method call. Handles requests
247 * by dbus clients for the object path of an specific network interface.
248 */
249DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
250					     struct wpa_global *global)
251{
252	DBusMessage *reply = NULL;
253	const char *ifname;
254	const char *path;
255	struct wpa_supplicant *wpa_s;
256
257	if (!dbus_message_get_args(message, NULL,
258				   DBUS_TYPE_STRING, &ifname,
259				   DBUS_TYPE_INVALID)) {
260		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
261		goto out;
262	}
263
264	wpa_s = wpa_supplicant_get_iface(global, ifname);
265	if (wpa_s == NULL) {
266		reply = wpas_dbus_new_invalid_iface_error(message);
267		goto out;
268	}
269
270	path = wpa_s->dbus_path;
271	reply = dbus_message_new_method_return(message);
272	dbus_message_append_args(reply,
273				 DBUS_TYPE_OBJECT_PATH, &path,
274				 DBUS_TYPE_INVALID);
275
276out:
277	return reply;
278}
279
280
281/**
282 * wpas_dbus_global_set_debugparams- Set the debug params
283 * @message: Pointer to incoming dbus message
284 * @global: %wpa_supplicant global data structure
285 * Returns: a dbus message containing a UINT32 indicating success (1) or
286 *          failure (0), or returns a dbus error message with more information
287 *
288 * Handler function for "setDebugParams" method call. Handles requests
289 * by dbus clients for the object path of an specific network interface.
290 */
291DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
292					       struct wpa_global *global)
293{
294	DBusMessage *reply = NULL;
295	int debug_level;
296	dbus_bool_t debug_timestamp;
297	dbus_bool_t debug_show_keys;
298
299	if (!dbus_message_get_args(message, NULL,
300				   DBUS_TYPE_INT32, &debug_level,
301				   DBUS_TYPE_BOOLEAN, &debug_timestamp,
302				   DBUS_TYPE_BOOLEAN, &debug_show_keys,
303				   DBUS_TYPE_INVALID)) {
304		return wpas_dbus_new_invalid_opts_error(message, NULL);
305	}
306
307	if (wpa_supplicant_set_debug_params(global, debug_level,
308					    debug_timestamp ? 1 : 0,
309					    debug_show_keys ? 1 : 0)) {
310		return wpas_dbus_new_invalid_opts_error(message, NULL);
311	}
312
313	reply = wpas_dbus_new_success_reply(message);
314
315	return reply;
316}
317
318
319/**
320 * wpas_dbus_iface_scan - Request a wireless scan on an interface
321 * @message: Pointer to incoming dbus message
322 * @wpa_s: wpa_supplicant structure for a network interface
323 * Returns: a dbus message containing a UINT32 indicating success (1) or
324 *          failure (0)
325 *
326 * Handler function for "scan" method call of a network device. Requests
327 * that wpa_supplicant perform a wireless scan as soon as possible
328 * on a particular wireless interface.
329 */
330DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
331				   struct wpa_supplicant *wpa_s)
332{
333	wpa_s->scan_req = MANUAL_SCAN_REQ;
334	wpa_supplicant_req_scan(wpa_s, 0, 0);
335	return wpas_dbus_new_success_reply(message);
336}
337
338
339/**
340 * wpas_dbus_iface_scan_results - Get the results of a recent scan request
341 * @message: Pointer to incoming dbus message
342 * @wpa_s: wpa_supplicant structure for a network interface
343 * Returns: a dbus message containing a dbus array of objects paths, or returns
344 *          a dbus error message if not scan results could be found
345 *
346 * Handler function for "scanResults" method call of a network device. Returns
347 * a dbus message containing the object paths of wireless networks found.
348 */
349DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
350					   struct wpa_supplicant *wpa_s)
351{
352	DBusMessage *reply;
353	DBusMessageIter iter;
354	DBusMessageIter sub_iter;
355	struct wpa_bss *bss;
356
357	/* Create and initialize the return message */
358	reply = dbus_message_new_method_return(message);
359	dbus_message_iter_init_append(reply, &iter);
360	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
361					      DBUS_TYPE_OBJECT_PATH_AS_STRING,
362					      &sub_iter))
363		goto error;
364
365	/* Loop through scan results and append each result's object path */
366	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
367		char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
368		char *path = path_buf;
369
370		/* Construct the object path for this network.  Note that ':'
371		 * is not a valid character in dbus object paths.
372		 */
373		os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
374			    "%s/" WPAS_DBUS_BSSIDS_PART "/"
375			    WPAS_DBUS_BSSID_FORMAT,
376			    wpa_s->dbus_path, MAC2STR(bss->bssid));
377		if (!dbus_message_iter_append_basic(&sub_iter,
378						    DBUS_TYPE_OBJECT_PATH,
379						    &path))
380			goto error;
381	}
382
383	if (!dbus_message_iter_close_container(&iter, &sub_iter))
384		goto error;
385
386	return reply;
387
388error:
389	dbus_message_unref(reply);
390	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
391				      "an internal error occurred returning scan results");
392}
393
394
395/**
396 * wpas_dbus_bssid_properties - Return the properties of a scanned network
397 * @message: Pointer to incoming dbus message
398 * @wpa_s: wpa_supplicant structure for a network interface
399 * @res: wpa_supplicant scan result for which to get properties
400 * Returns: a dbus message containing the properties for the requested network
401 *
402 * Handler function for "properties" method call of a scanned network.
403 * Returns a dbus message containing the the properties.
404 */
405DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
406					 struct wpa_supplicant *wpa_s,
407					 struct wpa_bss *bss)
408{
409	DBusMessage *reply;
410	DBusMessageIter iter, iter_dict;
411	const u8 *wpa_ie, *rsn_ie, *wps_ie;
412
413	/* Dump the properties into a dbus message */
414	reply = dbus_message_new_method_return(message);
415
416	wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
417	rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
418	wps_ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
419
420	dbus_message_iter_init_append(reply, &iter);
421	if (!wpa_dbus_dict_open_write(&iter, &iter_dict) ||
422	    !wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
423					     (const char *) bss->bssid,
424					     ETH_ALEN) ||
425	    !wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
426					     (const char *) bss->ssid,
427					     bss->ssid_len) ||
428	    (wpa_ie &&
429	     !wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
430					      (const char *) wpa_ie,
431					      wpa_ie[1] + 2)) ||
432	    (rsn_ie &&
433	     !wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
434					      (const char *) rsn_ie,
435					      rsn_ie[1] + 2)) ||
436	    (wps_ie &&
437	     !wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
438					     (const char *) wps_ie,
439					      wps_ie[1] + 2)) ||
440	    (bss->freq &&
441	     !wpa_dbus_dict_append_int32(&iter_dict, "frequency", bss->freq)) ||
442	    !wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
443					 bss->caps) ||
444	    (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
445	     !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) ||
446	    (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
447	     !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) ||
448	    (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
449	     !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) ||
450	    !wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
451					wpa_bss_get_max_rate(bss) * 500000) ||
452	    !wpa_dbus_dict_close_write(&iter, &iter_dict)) {
453		if (reply)
454			dbus_message_unref(reply);
455		reply = dbus_message_new_error(
456			message, WPAS_ERROR_INTERNAL_ERROR,
457			"an internal error occurred returning BSSID properties.");
458	}
459
460	return reply;
461}
462
463
464/**
465 * wpas_dbus_iface_capabilities - Return interface capabilities
466 * @message: Pointer to incoming dbus message
467 * @wpa_s: wpa_supplicant structure for a network interface
468 * Returns: A dbus message containing a dict of strings
469 *
470 * Handler function for "capabilities" method call of an interface.
471 */
472DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
473					   struct wpa_supplicant *wpa_s)
474{
475	DBusMessage *reply = NULL;
476	struct wpa_driver_capa capa;
477	int res;
478	DBusMessageIter iter, iter_dict;
479	char **eap_methods;
480	size_t num_items;
481	dbus_bool_t strict = FALSE;
482	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
483
484	if (!dbus_message_get_args(message, NULL,
485				   DBUS_TYPE_BOOLEAN, &strict,
486				   DBUS_TYPE_INVALID))
487		strict = FALSE;
488
489	reply = dbus_message_new_method_return(message);
490
491	dbus_message_iter_init_append(reply, &iter);
492	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
493		goto error;
494
495	/* EAP methods */
496	eap_methods = eap_get_names_as_string_array(&num_items);
497	if (eap_methods) {
498		dbus_bool_t success = FALSE;
499		size_t i = 0;
500
501		success = wpa_dbus_dict_append_string_array(
502			&iter_dict, "eap", (const char **) eap_methods,
503			num_items);
504
505		/* free returned method array */
506		while (eap_methods[i])
507			os_free(eap_methods[i++]);
508		os_free(eap_methods);
509
510		if (!success)
511			goto error;
512	}
513
514	res = wpa_drv_get_capa(wpa_s, &capa);
515
516	/***** pairwise cipher */
517	if (res < 0) {
518		if (!strict) {
519			const char *args[] = {"CCMP", "TKIP", "NONE"};
520
521			if (!wpa_dbus_dict_append_string_array(
522				    &iter_dict, "pairwise", args,
523				    ARRAY_SIZE(args)))
524				goto error;
525		}
526	} else {
527		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
528						      &iter_dict_entry,
529						      &iter_dict_val,
530						      &iter_array) ||
531		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
532		     !wpa_dbus_dict_string_array_add_element(
533			     &iter_array, "CCMP")) ||
534		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
535		     !wpa_dbus_dict_string_array_add_element(
536			     &iter_array, "TKIP")) ||
537		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
538		     !wpa_dbus_dict_string_array_add_element(
539			     &iter_array, "NONE")) ||
540		    !wpa_dbus_dict_end_string_array(&iter_dict,
541						    &iter_dict_entry,
542						    &iter_dict_val,
543						    &iter_array))
544			goto error;
545	}
546
547	/***** group cipher */
548	if (res < 0) {
549		if (!strict) {
550			const char *args[] = {
551				"CCMP", "TKIP", "WEP104", "WEP40"
552			};
553
554			if (!wpa_dbus_dict_append_string_array(
555				    &iter_dict, "group", args,
556				    ARRAY_SIZE(args)))
557				goto error;
558		}
559	} else {
560		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
561						      &iter_dict_entry,
562						      &iter_dict_val,
563						      &iter_array))
564			goto error;
565
566		if (((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
567		     !wpa_dbus_dict_string_array_add_element(
568			     &iter_array, "CCMP")) ||
569		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
570		     !wpa_dbus_dict_string_array_add_element(
571			     &iter_array, "TKIP")) ||
572		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
573		     !wpa_dbus_dict_string_array_add_element(
574			     &iter_array, "WEP104")) ||
575		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
576		     !wpa_dbus_dict_string_array_add_element(
577			     &iter_array, "WEP40")) ||
578		    !wpa_dbus_dict_end_string_array(&iter_dict,
579						    &iter_dict_entry,
580						    &iter_dict_val,
581						    &iter_array))
582			goto error;
583	}
584
585	/***** key management */
586	if (res < 0) {
587		if (!strict) {
588			const char *args[] = {
589				"WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
590				"NONE"
591			};
592			if (!wpa_dbus_dict_append_string_array(
593				    &iter_dict, "key_mgmt", args,
594				    ARRAY_SIZE(args)))
595				goto error;
596		}
597	} else {
598		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
599						      &iter_dict_entry,
600						      &iter_dict_val,
601						      &iter_array) ||
602		    !wpa_dbus_dict_string_array_add_element(&iter_array,
603							    "NONE") ||
604		    !wpa_dbus_dict_string_array_add_element(&iter_array,
605							    "IEEE8021X") ||
606		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
607				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) &&
608		     !wpa_dbus_dict_string_array_add_element(
609			     &iter_array, "WPA-EAP")) ||
610		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
611				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
612		     !wpa_dbus_dict_string_array_add_element(
613			     &iter_array, "WPA-PSK")) ||
614		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
615		     !wpa_dbus_dict_string_array_add_element(
616			     &iter_array, "WPA-NONE")) ||
617		    !wpa_dbus_dict_end_string_array(&iter_dict,
618						    &iter_dict_entry,
619						    &iter_dict_val,
620						    &iter_array))
621			goto error;
622	}
623
624	/***** WPA protocol */
625	if (res < 0) {
626		if (!strict) {
627			const char *args[] = { "RSN", "WPA" };
628
629			if (!wpa_dbus_dict_append_string_array(
630				    &iter_dict, "proto", args,
631				    ARRAY_SIZE(args)))
632				goto error;
633		}
634	} else {
635		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
636						      &iter_dict_entry,
637						      &iter_dict_val,
638						      &iter_array) ||
639		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
640				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
641		     !wpa_dbus_dict_string_array_add_element(
642			     &iter_array, "RSN")) ||
643		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
644				       WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
645		     !wpa_dbus_dict_string_array_add_element(
646			     &iter_array, "WPA")) ||
647		    !wpa_dbus_dict_end_string_array(&iter_dict,
648						    &iter_dict_entry,
649						    &iter_dict_val,
650						    &iter_array))
651			goto error;
652	}
653
654	/***** auth alg */
655	if (res < 0) {
656		if (!strict) {
657			const char *args[] = { "OPEN", "SHARED", "LEAP" };
658
659			if (!wpa_dbus_dict_append_string_array(
660				    &iter_dict, "auth_alg", args,
661				    ARRAY_SIZE(args)))
662				goto error;
663		}
664	} else {
665		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
666						      &iter_dict_entry,
667						      &iter_dict_val,
668						      &iter_array) ||
669		    ((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
670		     !wpa_dbus_dict_string_array_add_element(
671			     &iter_array, "OPEN")) ||
672		    ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
673		     !wpa_dbus_dict_string_array_add_element(
674			     &iter_array, "SHARED")) ||
675		    ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
676		     !wpa_dbus_dict_string_array_add_element(
677			     &iter_array, "LEAP")) ||
678		    !wpa_dbus_dict_end_string_array(&iter_dict,
679						    &iter_dict_entry,
680						    &iter_dict_val,
681						    &iter_array))
682			goto error;
683	}
684
685	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
686		goto error;
687
688	return reply;
689
690error:
691	if (reply)
692		dbus_message_unref(reply);
693	return dbus_message_new_error(
694		message, WPAS_ERROR_INTERNAL_ERROR,
695		"an internal error occurred returning interface capabilities.");
696}
697
698
699/**
700 * wpas_dbus_iface_add_network - Add a new configured network
701 * @message: Pointer to incoming dbus message
702 * @wpa_s: wpa_supplicant structure for a network interface
703 * Returns: A dbus message containing the object path of the new network
704 *
705 * Handler function for "addNetwork" method call of a network interface.
706 */
707DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
708					  struct wpa_supplicant *wpa_s)
709{
710	DBusMessage *reply = NULL;
711	struct wpa_ssid *ssid;
712	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
713
714	ssid = wpa_config_add_network(wpa_s->conf);
715	if (ssid == NULL) {
716		reply = dbus_message_new_error(
717			message, WPAS_ERROR_ADD_NETWORK_ERROR,
718			"wpa_supplicant could not add a network on this interface.");
719		goto out;
720	}
721	wpas_notify_network_added(wpa_s, ssid);
722	ssid->disabled = 1;
723	wpa_config_set_network_defaults(ssid);
724
725	/* Construct the object path for this network. */
726	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
727		    "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
728		    wpa_s->dbus_path, ssid->id);
729
730	reply = dbus_message_new_method_return(message);
731	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
732				 &path, DBUS_TYPE_INVALID);
733
734out:
735	return reply;
736}
737
738
739/**
740 * wpas_dbus_iface_remove_network - Remove a configured network
741 * @message: Pointer to incoming dbus message
742 * @wpa_s: wpa_supplicant structure for a network interface
743 * Returns: A dbus message containing a UINT32 indicating success (1) or
744 *          failure (0)
745 *
746 * Handler function for "removeNetwork" method call of a network interface.
747 */
748DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
749					     struct wpa_supplicant *wpa_s)
750{
751	DBusMessage *reply = NULL;
752	const char *op;
753	char *iface = NULL, *net_id = NULL;
754	int id;
755	struct wpa_ssid *ssid;
756
757	if (!dbus_message_get_args(message, NULL,
758				   DBUS_TYPE_OBJECT_PATH, &op,
759				   DBUS_TYPE_INVALID)) {
760		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
761		goto out;
762	}
763
764	/* Extract the network ID */
765	iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
766	if (iface == NULL || net_id == NULL) {
767		reply = wpas_dbus_new_invalid_network_error(message);
768		goto out;
769	}
770
771	/* Ensure the network is actually a child of this interface */
772	if (os_strcmp(iface, wpa_s->dbus_path) != 0) {
773		reply = wpas_dbus_new_invalid_network_error(message);
774		goto out;
775	}
776
777	id = strtoul(net_id, NULL, 10);
778	ssid = wpa_config_get_network(wpa_s->conf, id);
779	if (ssid == NULL) {
780		reply = wpas_dbus_new_invalid_network_error(message);
781		goto out;
782	}
783
784	wpas_notify_network_removed(wpa_s, ssid);
785
786	if (ssid == wpa_s->current_ssid)
787		wpa_supplicant_deauthenticate(wpa_s,
788					      WLAN_REASON_DEAUTH_LEAVING);
789
790	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
791		reply = dbus_message_new_error(
792			message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
793			"error removing the specified on this interface.");
794		goto out;
795	}
796
797	reply = wpas_dbus_new_success_reply(message);
798
799out:
800	os_free(iface);
801	os_free(net_id);
802	return reply;
803}
804
805
806static const char  const *dont_quote[] = {
807	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
808	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
809	"bssid", NULL
810};
811
812
813static dbus_bool_t should_quote_opt(const char *key)
814{
815	int i = 0;
816
817	while (dont_quote[i] != NULL) {
818		if (os_strcmp(key, dont_quote[i]) == 0)
819			return FALSE;
820		i++;
821	}
822	return TRUE;
823}
824
825
826/**
827 * wpas_dbus_iface_set_network - Set options for a configured network
828 * @message: Pointer to incoming dbus message
829 * @wpa_s: wpa_supplicant structure for a network interface
830 * @ssid: wpa_ssid structure for a configured network
831 * Returns: a dbus message containing a UINT32 indicating success (1) or
832 *          failure (0)
833 *
834 * Handler function for "set" method call of a configured network.
835 */
836DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
837					  struct wpa_supplicant *wpa_s,
838					  struct wpa_ssid *ssid)
839{
840	DBusMessage *reply = NULL;
841	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
842	DBusMessageIter	iter, iter_dict;
843
844	dbus_message_iter_init(message, &iter);
845
846	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
847		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
848		goto out;
849	}
850
851	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
852		char *value = NULL;
853		size_t size = 50;
854		int ret;
855
856		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
857			reply = wpas_dbus_new_invalid_opts_error(message,
858								 NULL);
859			goto out;
860		}
861
862		/* Type conversions, since wpa_supplicant wants strings */
863		if (entry.type == DBUS_TYPE_ARRAY &&
864		    entry.array_type == DBUS_TYPE_BYTE) {
865			if (entry.array_len <= 0)
866				goto error;
867
868			size = entry.array_len * 2 + 1;
869			value = os_zalloc(size);
870			if (value == NULL)
871				goto error;
872			ret = wpa_snprintf_hex(value, size,
873					       (u8 *) entry.bytearray_value,
874					       entry.array_len);
875			if (ret <= 0)
876				goto error;
877		} else if (entry.type == DBUS_TYPE_STRING) {
878			if (should_quote_opt(entry.key)) {
879				size = os_strlen(entry.str_value);
880				/* Zero-length option check */
881				if (size <= 0)
882					goto error;
883				size += 3;  /* For quotes and terminator */
884				value = os_zalloc(size);
885				if (value == NULL)
886					goto error;
887				ret = os_snprintf(value, size, "\"%s\"",
888						  entry.str_value);
889				if (os_snprintf_error(size, ret))
890					goto error;
891			} else {
892				value = os_strdup(entry.str_value);
893				if (value == NULL)
894					goto error;
895			}
896		} else if (entry.type == DBUS_TYPE_UINT32) {
897			value = os_zalloc(size);
898			if (value == NULL)
899				goto error;
900			ret = os_snprintf(value, size, "%u",
901					  entry.uint32_value);
902			if (os_snprintf_error(size, ret))
903				goto error;
904		} else if (entry.type == DBUS_TYPE_INT32) {
905			value = os_zalloc(size);
906			if (value == NULL)
907				goto error;
908			ret = os_snprintf(value, size, "%d",
909					  entry.int32_value);
910			if (os_snprintf_error(size, ret))
911				goto error;
912		} else
913			goto error;
914
915		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
916			goto error;
917
918		if ((os_strcmp(entry.key, "psk") == 0 &&
919		     value[0] == '"' && ssid->ssid_len) ||
920		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
921			wpa_config_update_psk(ssid);
922		else if (os_strcmp(entry.key, "priority") == 0)
923			wpa_config_update_prio_list(wpa_s->conf);
924
925		os_free(value);
926		wpa_dbus_dict_entry_clear(&entry);
927		continue;
928
929	error:
930		os_free(value);
931		reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
932		wpa_dbus_dict_entry_clear(&entry);
933		break;
934	}
935
936	if (!reply)
937		reply = wpas_dbus_new_success_reply(message);
938
939out:
940	return reply;
941}
942
943
944/**
945 * wpas_dbus_iface_enable_network - Mark a configured network as enabled
946 * @message: Pointer to incoming dbus message
947 * @wpa_s: wpa_supplicant structure for a network interface
948 * @ssid: wpa_ssid structure for a configured network
949 * Returns: A dbus message containing a UINT32 indicating success (1) or
950 *          failure (0)
951 *
952 * Handler function for "enable" method call of a configured network.
953 */
954DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
955					     struct wpa_supplicant *wpa_s,
956					     struct wpa_ssid *ssid)
957{
958	wpa_supplicant_enable_network(wpa_s, ssid);
959	return wpas_dbus_new_success_reply(message);
960}
961
962
963/**
964 * wpas_dbus_iface_disable_network - Mark a configured network as disabled
965 * @message: Pointer to incoming dbus message
966 * @wpa_s: wpa_supplicant structure for a network interface
967 * @ssid: wpa_ssid structure for a configured network
968 * Returns: A dbus message containing a UINT32 indicating success (1) or
969 *          failure (0)
970 *
971 * Handler function for "disable" method call of a configured network.
972 */
973DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
974					      struct wpa_supplicant *wpa_s,
975					      struct wpa_ssid *ssid)
976{
977	wpa_supplicant_disable_network(wpa_s, ssid);
978	return wpas_dbus_new_success_reply(message);
979}
980
981
982/**
983 * wpas_dbus_iface_select_network - Attempt association with a configured network
984 * @message: Pointer to incoming dbus message
985 * @wpa_s: wpa_supplicant structure for a network interface
986 * Returns: A dbus message containing a UINT32 indicating success (1) or
987 *          failure (0)
988 *
989 * Handler function for "selectNetwork" method call of network interface.
990 */
991DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
992					     struct wpa_supplicant *wpa_s)
993{
994	DBusMessage *reply = NULL;
995	const char *op;
996	struct wpa_ssid *ssid;
997	char *iface_obj_path = NULL;
998	char *network = NULL;
999
1000	if (os_strlen(dbus_message_get_signature(message)) == 0) {
1001		/* Any network */
1002		ssid = NULL;
1003	} else {
1004		int nid;
1005
1006		if (!dbus_message_get_args(message, NULL,
1007					   DBUS_TYPE_OBJECT_PATH, &op,
1008					   DBUS_TYPE_INVALID)) {
1009			reply = wpas_dbus_new_invalid_opts_error(message,
1010								 NULL);
1011			goto out;
1012		}
1013
1014		/* Extract the network number */
1015		iface_obj_path = wpas_dbus_decompose_object_path(op,
1016								 &network,
1017								 NULL);
1018		if (iface_obj_path == NULL) {
1019			reply = wpas_dbus_new_invalid_iface_error(message);
1020			goto out;
1021		}
1022		/* Ensure the object path really points to this interface */
1023		if (network == NULL ||
1024		    os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
1025			reply = wpas_dbus_new_invalid_network_error(message);
1026			goto out;
1027		}
1028
1029		nid = strtoul(network, NULL, 10);
1030		if (errno == EINVAL) {
1031			reply = wpas_dbus_new_invalid_network_error(message);
1032			goto out;
1033		}
1034
1035		ssid = wpa_config_get_network(wpa_s->conf, nid);
1036		if (ssid == NULL) {
1037			reply = wpas_dbus_new_invalid_network_error(message);
1038			goto out;
1039		}
1040	}
1041
1042	/* Finally, associate with the network */
1043	wpa_supplicant_select_network(wpa_s, ssid);
1044
1045	reply = wpas_dbus_new_success_reply(message);
1046
1047out:
1048	os_free(iface_obj_path);
1049	os_free(network);
1050	return reply;
1051}
1052
1053
1054/**
1055 * wpas_dbus_iface_disconnect - Terminate the current connection
1056 * @message: Pointer to incoming dbus message
1057 * @wpa_s: wpa_supplicant structure for a network interface
1058 * Returns: A dbus message containing a UINT32 indicating success (1) or
1059 *          failure (0)
1060 *
1061 * Handler function for "disconnect" method call of network interface.
1062 */
1063DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
1064					 struct wpa_supplicant *wpa_s)
1065{
1066	wpa_s->disconnected = 1;
1067	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1068
1069	return wpas_dbus_new_success_reply(message);
1070}
1071
1072
1073/**
1074 * wpas_dbus_iface_set_ap_scan - Control roaming mode
1075 * @message: Pointer to incoming dbus message
1076 * @wpa_s: wpa_supplicant structure for a network interface
1077 * Returns: A dbus message containing a UINT32 indicating success (1) or
1078 *          failure (0)
1079 *
1080 * Handler function for "setAPScan" method call.
1081 */
1082DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
1083					  struct wpa_supplicant *wpa_s)
1084{
1085	DBusMessage *reply = NULL;
1086	dbus_uint32_t ap_scan = 1;
1087
1088	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
1089				   DBUS_TYPE_INVALID)) {
1090		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1091		goto out;
1092	}
1093
1094	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
1095		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1096		goto out;
1097	}
1098
1099	reply = wpas_dbus_new_success_reply(message);
1100
1101out:
1102	return reply;
1103}
1104
1105
1106/**
1107 * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
1108 * @message: Pointer to incoming dbus message
1109 * @wpa_s: wpa_supplicant structure for a network interface
1110 * Returns: A dbus message containing a UINT32 indicating success (1) or
1111 *          failure (0)
1112 *
1113 * Handler function for "setSmartcardModules" method call.
1114 */
1115DBusMessage * wpas_dbus_iface_set_smartcard_modules(
1116	DBusMessage *message, struct wpa_supplicant *wpa_s)
1117{
1118	DBusMessageIter iter, iter_dict;
1119	char *opensc_engine_path = NULL;
1120	char *pkcs11_engine_path = NULL;
1121	char *pkcs11_module_path = NULL;
1122	struct wpa_dbus_dict_entry entry;
1123
1124	if (!dbus_message_iter_init(message, &iter))
1125		goto error;
1126
1127	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1128		goto error;
1129
1130	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1131		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1132			goto error;
1133		if (!strcmp(entry.key, "opensc_engine_path") &&
1134		    entry.type == DBUS_TYPE_STRING) {
1135			os_free(opensc_engine_path);
1136			opensc_engine_path = os_strdup(entry.str_value);
1137			wpa_dbus_dict_entry_clear(&entry);
1138			if (opensc_engine_path == NULL)
1139				goto error;
1140		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
1141			   entry.type == DBUS_TYPE_STRING) {
1142			os_free(pkcs11_engine_path);
1143			pkcs11_engine_path = os_strdup(entry.str_value);
1144			wpa_dbus_dict_entry_clear(&entry);
1145			if (pkcs11_engine_path == NULL)
1146				goto error;
1147		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
1148				 entry.type == DBUS_TYPE_STRING) {
1149			os_free(pkcs11_module_path);
1150			pkcs11_module_path = os_strdup(entry.str_value);
1151			wpa_dbus_dict_entry_clear(&entry);
1152			if (pkcs11_module_path == NULL)
1153				goto error;
1154		} else {
1155			wpa_dbus_dict_entry_clear(&entry);
1156			goto error;
1157		}
1158	}
1159
1160	os_free(wpa_s->conf->opensc_engine_path);
1161	wpa_s->conf->opensc_engine_path = opensc_engine_path;
1162	os_free(wpa_s->conf->pkcs11_engine_path);
1163	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
1164	os_free(wpa_s->conf->pkcs11_module_path);
1165	wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
1166
1167	wpa_sm_set_eapol(wpa_s->wpa, NULL);
1168	eapol_sm_deinit(wpa_s->eapol);
1169	wpa_s->eapol = NULL;
1170	wpa_supplicant_init_eapol(wpa_s);
1171	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
1172
1173	return wpas_dbus_new_success_reply(message);
1174
1175error:
1176	os_free(opensc_engine_path);
1177	os_free(pkcs11_engine_path);
1178	os_free(pkcs11_module_path);
1179	return wpas_dbus_new_invalid_opts_error(message, NULL);
1180}
1181
1182
1183/**
1184 * wpas_dbus_iface_get_state - Get interface state
1185 * @message: Pointer to incoming dbus message
1186 * @wpa_s: wpa_supplicant structure for a network interface
1187 * Returns: A dbus message containing a STRING representing the current
1188 *          interface state
1189 *
1190 * Handler function for "state" method call.
1191 */
1192DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
1193					struct wpa_supplicant *wpa_s)
1194{
1195	DBusMessage *reply = NULL;
1196	const char *str_state;
1197
1198	reply = dbus_message_new_method_return(message);
1199	if (reply != NULL) {
1200		str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
1201		dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
1202					 DBUS_TYPE_INVALID);
1203	}
1204
1205	return reply;
1206}
1207
1208
1209/**
1210 * wpas_dbus_iface_get_scanning - Get interface scanning state
1211 * @message: Pointer to incoming dbus message
1212 * @wpa_s: wpa_supplicant structure for a network interface
1213 * Returns: A dbus message containing whether the interface is scanning
1214 *
1215 * Handler function for "scanning" method call.
1216 */
1217DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
1218					   struct wpa_supplicant *wpa_s)
1219{
1220	DBusMessage *reply = NULL;
1221	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
1222
1223	reply = dbus_message_new_method_return(message);
1224	if (reply != NULL) {
1225		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
1226					 DBUS_TYPE_INVALID);
1227	} else {
1228		wpa_printf(MSG_ERROR,
1229			   "dbus: Not enough memory to return scanning state");
1230	}
1231
1232	return reply;
1233}
1234
1235
1236#ifndef CONFIG_NO_CONFIG_BLOBS
1237
1238/**
1239 * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
1240 * @message: Pointer to incoming dbus message
1241 * @wpa_s: %wpa_supplicant data structure
1242 * Returns: A dbus message containing a UINT32 indicating success (1) or
1243 *          failure (0)
1244 *
1245 * Asks wpa_supplicant to internally store a one or more binary blobs.
1246 */
1247DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
1248					struct wpa_supplicant *wpa_s)
1249{
1250	DBusMessage *reply = NULL;
1251	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1252	DBusMessageIter	iter, iter_dict;
1253
1254	dbus_message_iter_init(message, &iter);
1255
1256	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1257		return wpas_dbus_new_invalid_opts_error(message, NULL);
1258
1259	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1260		struct wpa_config_blob *blob;
1261
1262		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1263			reply = wpas_dbus_new_invalid_opts_error(message,
1264								 NULL);
1265			break;
1266		}
1267
1268		if (entry.type != DBUS_TYPE_ARRAY ||
1269		    entry.array_type != DBUS_TYPE_BYTE) {
1270			reply = wpas_dbus_new_invalid_opts_error(
1271				message, "Byte array expected.");
1272			break;
1273		}
1274
1275		if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
1276		    !strlen(entry.key)) {
1277			reply = wpas_dbus_new_invalid_opts_error(
1278				message, "Invalid array size.");
1279			break;
1280		}
1281
1282		blob = os_zalloc(sizeof(*blob));
1283		if (blob == NULL) {
1284			reply = dbus_message_new_error(
1285				message, WPAS_ERROR_ADD_ERROR,
1286				"Not enough memory to add blob.");
1287			break;
1288		}
1289		blob->data = os_zalloc(entry.array_len);
1290		if (blob->data == NULL) {
1291			reply = dbus_message_new_error(
1292				message, WPAS_ERROR_ADD_ERROR,
1293				"Not enough memory to add blob data.");
1294			os_free(blob);
1295			break;
1296		}
1297
1298		blob->name = os_strdup(entry.key);
1299		blob->len = entry.array_len;
1300		os_memcpy(blob->data, (u8 *) entry.bytearray_value,
1301				entry.array_len);
1302		if (blob->name == NULL) {
1303			wpa_config_free_blob(blob);
1304			reply = dbus_message_new_error(
1305				message, WPAS_ERROR_ADD_ERROR,
1306				"Error adding blob.");
1307			break;
1308		}
1309
1310		/* Success */
1311		if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
1312			wpas_notify_blob_removed(wpa_s, blob->name);
1313		wpa_config_set_blob(wpa_s->conf, blob);
1314		wpas_notify_blob_added(wpa_s, blob->name);
1315
1316		wpa_dbus_dict_entry_clear(&entry);
1317	}
1318	wpa_dbus_dict_entry_clear(&entry);
1319
1320	return reply ? reply : wpas_dbus_new_success_reply(message);
1321}
1322
1323
1324/**
1325 * wpas_dbus_iface_remove_blob - Remove named binary blobs
1326 * @message: Pointer to incoming dbus message
1327 * @wpa_s: %wpa_supplicant data structure
1328 * Returns: A dbus message containing a UINT32 indicating success (1) or
1329 *          failure (0)
1330 *
1331 * Asks wpa_supplicant to remove one or more previously stored binary blobs.
1332 */
1333DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
1334					   struct wpa_supplicant *wpa_s)
1335{
1336	DBusMessageIter iter, array;
1337	char *err_msg = NULL;
1338
1339	dbus_message_iter_init(message, &iter);
1340
1341	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1342	    dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
1343		return wpas_dbus_new_invalid_opts_error(message, NULL);
1344
1345	dbus_message_iter_recurse(&iter, &array);
1346	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
1347		const char *name;
1348
1349		dbus_message_iter_get_basic(&array, &name);
1350		if (!os_strlen(name))
1351			err_msg = "Invalid blob name.";
1352		else if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
1353			err_msg = "Error removing blob.";
1354		else
1355			wpas_notify_blob_removed(wpa_s, name);
1356		dbus_message_iter_next(&array);
1357	}
1358
1359	if (err_msg)
1360		return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
1361					      err_msg);
1362
1363	return wpas_dbus_new_success_reply(message);
1364}
1365
1366#endif /* CONFIG_NO_CONFIG_BLOBS */
1367
1368
1369/**
1370 * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
1371 * @message: Pointer to incoming dbus message
1372 * @wpa_s: %wpa_supplicant data structure
1373 * Returns: a dbus message containing a UINT32 indicating success (1) or
1374 *          failure (0), or returns a dbus error message with more information
1375 *
1376 * Handler function for "flush" method call. Handles requests for an
1377 * interface with an optional "age" parameter that specifies the minimum
1378 * age of a BSS to be flushed.
1379 */
1380DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
1381				    struct wpa_supplicant *wpa_s)
1382{
1383	int flush_age = 0;
1384
1385	if (os_strlen(dbus_message_get_signature(message)) != 0 &&
1386	    !dbus_message_get_args(message, NULL,
1387				   DBUS_TYPE_INT32, &flush_age,
1388				   DBUS_TYPE_INVALID)) {
1389		return wpas_dbus_new_invalid_opts_error(message, NULL);
1390	}
1391
1392	if (flush_age == 0)
1393		wpa_bss_flush(wpa_s);
1394	else
1395		wpa_bss_flush_by_age(wpa_s, flush_age);
1396
1397	return wpas_dbus_new_success_reply(message);
1398}
1399