• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * WPA Supplicant / dbus-based control interface
3  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4  * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
5  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6  *
7  * This software may be distributed under the terms of the BSD license.
8  * See README for more details.
9  */
10 
11 #include "includes.h"
12 
13 #include "common.h"
14 #include "common/ieee802_11_defs.h"
15 #include "eap_peer/eap_methods.h"
16 #include "eapol_supp/eapol_supp_sm.h"
17 #include "rsn_supp/wpa.h"
18 #include "../config.h"
19 #include "../wpa_supplicant_i.h"
20 #include "../driver_i.h"
21 #include "../notify.h"
22 #include "../bss.h"
23 #include "../scan.h"
24 #include "../autoscan.h"
25 #include "dbus_new_helpers.h"
26 #include "dbus_new.h"
27 #include "dbus_new_handlers.h"
28 #include "dbus_dict_helpers.h"
29 #include "dbus_common_i.h"
30 
31 static const char *debug_strings[] = {
32 	"excessive", "msgdump", "debug", "info", "warning", "error", NULL
33 };
34 
35 
36 /**
37  * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
38  * @message: Pointer to incoming dbus message this error refers to
39  * @arg: Optional string appended to error message
40  * Returns: a dbus error message
41  *
42  * Convenience function to create and return an UnknownError
43  */
wpas_dbus_error_unknown_error(DBusMessage * message,const char * arg)44 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
45 					    const char *arg)
46 {
47 	/*
48 	 * This function can be called as a result of a failure
49 	 * within internal getter calls, which will call this function
50 	 * with a NULL message parameter.  However, dbus_message_new_error
51 	 * looks very unkindly (i.e, abort()) on a NULL message, so
52 	 * in this case, we should not call it.
53 	 */
54 	if (message == NULL) {
55 		wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error "
56 			   "called with NULL message (arg=%s)",
57 			   arg ? arg : "N/A");
58 		return NULL;
59 	}
60 
61 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
62 				      arg);
63 }
64 
65 
66 /**
67  * wpas_dbus_error_iface_unknown - Return a new invalid interface error message
68  * @message: Pointer to incoming dbus message this error refers to
69  * Returns: A dbus error message
70  *
71  * Convenience function to create and return an invalid interface error
72  */
wpas_dbus_error_iface_unknown(DBusMessage * message)73 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
74 {
75 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
76 				      "wpa_supplicant knows nothing about "
77 				      "this interface.");
78 }
79 
80 
81 /**
82  * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
83  * @message: Pointer to incoming dbus message this error refers to
84  * Returns: a dbus error message
85  *
86  * Convenience function to create and return an invalid network error
87  */
wpas_dbus_error_network_unknown(DBusMessage * message)88 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
89 {
90 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
91 				      "There is no such a network in this "
92 				      "interface.");
93 }
94 
95 
96 /**
97  * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
98  * @message: Pointer to incoming dbus message this error refers to
99  * Returns: a dbus error message
100  *
101  * Convenience function to create and return an invalid options error
102  */
wpas_dbus_error_invalid_args(DBusMessage * message,const char * arg)103 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
104 					  const char *arg)
105 {
106 	DBusMessage *reply;
107 
108 	reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
109 				       "Did not receive correct message "
110 				       "arguments.");
111 	if (arg != NULL)
112 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
113 					 DBUS_TYPE_INVALID);
114 
115 	return reply;
116 }
117 
118 
119 /**
120  * wpas_dbus_error_scan_error - Return a new ScanError error message
121  * @message: Pointer to incoming dbus message this error refers to
122  * @error: Optional string to be used as the error message
123  * Returns: a dbus error message
124  *
125  * Convenience function to create and return a scan error
126  */
wpas_dbus_error_scan_error(DBusMessage * message,const char * error)127 DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
128 					 const char *error)
129 {
130 	DBusMessage *reply;
131 
132 	reply = dbus_message_new_error(message,
133 				       WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
134 				       error);
135 
136 	return reply;
137 }
138 
139 
140 static const char *dont_quote[] = {
141 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
142 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
143 	"bssid", "scan_freq", "freq_list", NULL
144 };
145 
should_quote_opt(const char * key)146 static dbus_bool_t should_quote_opt(const char *key)
147 {
148 	int i = 0;
149 	while (dont_quote[i] != NULL) {
150 		if (os_strcmp(key, dont_quote[i]) == 0)
151 			return FALSE;
152 		i++;
153 	}
154 	return TRUE;
155 }
156 
157 /**
158  * get_iface_by_dbus_path - Get a new network interface
159  * @global: Pointer to global data from wpa_supplicant_init()
160  * @path: Pointer to a dbus object path representing an interface
161  * Returns: Pointer to the interface or %NULL if not found
162  */
get_iface_by_dbus_path(struct wpa_global * global,const char * path)163 static struct wpa_supplicant * get_iface_by_dbus_path(
164 	struct wpa_global *global, const char *path)
165 {
166 	struct wpa_supplicant *wpa_s;
167 
168 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
169 		if (os_strcmp(wpa_s->dbus_new_path, path) == 0)
170 			return wpa_s;
171 	}
172 	return NULL;
173 }
174 
175 
176 /**
177  * set_network_properties - Set properties of a configured network
178  * @wpa_s: wpa_supplicant structure for a network interface
179  * @ssid: wpa_ssid structure for a configured network
180  * @iter: DBus message iterator containing dictionary of network
181  * properties to set.
182  * @error: On failure, an error describing the failure
183  * Returns: TRUE if the request succeeds, FALSE if it failed
184  *
185  * Sets network configuration with parameters given id DBus dictionary
186  */
set_network_properties(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,DBusMessageIter * iter,DBusError * error)187 dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
188 				   struct wpa_ssid *ssid,
189 				   DBusMessageIter *iter,
190 				   DBusError *error)
191 {
192 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
193 	DBusMessageIter	iter_dict;
194 	char *value = NULL;
195 
196 	if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
197 		return FALSE;
198 
199 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
200 		size_t size = 50;
201 		int ret;
202 
203 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
204 			goto error;
205 
206 		value = NULL;
207 		if (entry.type == DBUS_TYPE_ARRAY &&
208 		    entry.array_type == DBUS_TYPE_BYTE) {
209 			if (entry.array_len <= 0)
210 				goto error;
211 
212 			size = entry.array_len * 2 + 1;
213 			value = os_zalloc(size);
214 			if (value == NULL)
215 				goto error;
216 
217 			ret = wpa_snprintf_hex(value, size,
218 					       (u8 *) entry.bytearray_value,
219 					       entry.array_len);
220 			if (ret <= 0)
221 				goto error;
222 		} else if (entry.type == DBUS_TYPE_STRING) {
223 			if (should_quote_opt(entry.key)) {
224 				size = os_strlen(entry.str_value);
225 				if (size <= 0)
226 					goto error;
227 
228 				size += 3;
229 				value = os_zalloc(size);
230 				if (value == NULL)
231 					goto error;
232 
233 				ret = os_snprintf(value, size, "\"%s\"",
234 						  entry.str_value);
235 				if (ret < 0 || (size_t) ret != (size - 1))
236 					goto error;
237 			} else {
238 				value = os_strdup(entry.str_value);
239 				if (value == NULL)
240 					goto error;
241 			}
242 		} else if (entry.type == DBUS_TYPE_UINT32) {
243 			value = os_zalloc(size);
244 			if (value == NULL)
245 				goto error;
246 
247 			ret = os_snprintf(value, size, "%u",
248 					  entry.uint32_value);
249 			if (ret <= 0)
250 				goto error;
251 		} else if (entry.type == DBUS_TYPE_INT32) {
252 			value = os_zalloc(size);
253 			if (value == NULL)
254 				goto error;
255 
256 			ret = os_snprintf(value, size, "%d",
257 					  entry.int32_value);
258 			if (ret <= 0)
259 				goto error;
260 		} else
261 			goto error;
262 
263 		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
264 			goto error;
265 
266 		if ((os_strcmp(entry.key, "psk") == 0 &&
267 		     value[0] == '"' && ssid->ssid_len) ||
268 		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
269 			wpa_config_update_psk(ssid);
270 		else if (os_strcmp(entry.key, "priority") == 0)
271 			wpa_config_update_prio_list(wpa_s->conf);
272 
273 		os_free(value);
274 		value = NULL;
275 		wpa_dbus_dict_entry_clear(&entry);
276 	}
277 
278 	return TRUE;
279 
280 error:
281 	os_free(value);
282 	wpa_dbus_dict_entry_clear(&entry);
283 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
284 			     "invalid message format");
285 	return FALSE;
286 }
287 
288 
289 /**
290  * wpas_dbus_simple_property_getter - Get basic type property
291  * @iter: Message iter to use when appending arguments
292  * @type: DBus type of property (must be basic type)
293  * @val: pointer to place holding property value
294  * @error: On failure an error describing the failure
295  * Returns: TRUE if the request was successful, FALSE if it failed
296  *
297  * Generic getter for basic type properties. Type is required to be basic.
298  */
wpas_dbus_simple_property_getter(DBusMessageIter * iter,const int type,const void * val,DBusError * error)299 dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
300 					     const int type,
301 					     const void *val,
302 					     DBusError *error)
303 {
304 	DBusMessageIter variant_iter;
305 
306 	if (!dbus_type_is_basic(type)) {
307 		dbus_set_error(error, DBUS_ERROR_FAILED,
308 		               "%s: given type is not basic", __func__);
309 		return FALSE;
310 	}
311 
312 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
313 	                                      wpa_dbus_type_as_string(type),
314 	                                      &variant_iter))
315 		goto error;
316 
317 	if (!dbus_message_iter_append_basic(&variant_iter, type, val))
318 		goto error;
319 
320 	if (!dbus_message_iter_close_container(iter, &variant_iter))
321 		goto error;
322 
323 	return TRUE;
324 
325 error:
326 	dbus_set_error(error, DBUS_ERROR_FAILED,
327 	               "%s: error constructing reply", __func__);
328 	return FALSE;
329 }
330 
331 
332 /**
333  * wpas_dbus_simple_property_setter - Set basic type property
334  * @message: Pointer to incoming dbus message
335  * @type: DBus type of property (must be basic type)
336  * @val: pointer to place where value being set will be stored
337  * Returns: TRUE if the request was successful, FALSE if it failed
338  *
339  * Generic setter for basic type properties. Type is required to be basic.
340  */
wpas_dbus_simple_property_setter(DBusMessageIter * iter,DBusError * error,const int type,void * val)341 dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
342 					     DBusError *error,
343 					     const int type, void *val)
344 {
345 	DBusMessageIter variant_iter;
346 
347 	if (!dbus_type_is_basic(type)) {
348 		dbus_set_error(error, DBUS_ERROR_FAILED,
349 			       "%s: given type is not basic", __func__);
350 		return FALSE;
351 	}
352 
353 	/* Look at the new value */
354 	dbus_message_iter_recurse(iter, &variant_iter);
355 	if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
356 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
357 				     "wrong property type");
358 		return FALSE;
359 	}
360 	dbus_message_iter_get_basic(&variant_iter, val);
361 
362 	return TRUE;
363 }
364 
365 
366 /**
367  * wpas_dbus_simple_array_property_getter - Get array type property
368  * @iter: Pointer to incoming dbus message iterator
369  * @type: DBus type of property array elements (must be basic type)
370  * @array: pointer to array of elements to put into response message
371  * @array_len: length of above array
372  * @error: a pointer to an error to fill on failure
373  * Returns: TRUE if the request succeeded, FALSE if it failed
374  *
375  * Generic getter for array type properties. Array elements type is
376  * required to be basic.
377  */
wpas_dbus_simple_array_property_getter(DBusMessageIter * iter,const int type,const void * array,size_t array_len,DBusError * error)378 dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
379 						   const int type,
380 						   const void *array,
381 						   size_t array_len,
382 						   DBusError *error)
383 {
384 	DBusMessageIter variant_iter, array_iter;
385 	char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
386 	const char *sub_type_str;
387 	size_t element_size, i;
388 
389 	if (!dbus_type_is_basic(type)) {
390 		dbus_set_error(error, DBUS_ERROR_FAILED,
391 		               "%s: given type is not basic", __func__);
392 		return FALSE;
393 	}
394 
395 	sub_type_str = wpa_dbus_type_as_string(type);
396 	type_str[1] = sub_type_str[0];
397 
398 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
399 					      type_str, &variant_iter)) {
400 		dbus_set_error(error, DBUS_ERROR_FAILED,
401 		               "%s: failed to construct message 1", __func__);
402 		return FALSE;
403 	}
404 
405 	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
406 					      sub_type_str, &array_iter)) {
407 		dbus_set_error(error, DBUS_ERROR_FAILED,
408 		               "%s: failed to construct message 2", __func__);
409 		return FALSE;
410 	}
411 
412 	switch(type) {
413 	case DBUS_TYPE_BYTE:
414 	case DBUS_TYPE_BOOLEAN:
415 		element_size = 1;
416 		break;
417 	case DBUS_TYPE_INT16:
418 	case DBUS_TYPE_UINT16:
419 		element_size = sizeof(uint16_t);
420 		break;
421 	case DBUS_TYPE_INT32:
422 	case DBUS_TYPE_UINT32:
423 		element_size = sizeof(uint32_t);
424 		break;
425 	case DBUS_TYPE_INT64:
426 	case DBUS_TYPE_UINT64:
427 		element_size = sizeof(uint64_t);
428 		break;
429 	case DBUS_TYPE_DOUBLE:
430 		element_size = sizeof(double);
431 		break;
432 	case DBUS_TYPE_STRING:
433 	case DBUS_TYPE_OBJECT_PATH:
434 		element_size = sizeof(char *);
435 		break;
436 	default:
437 		dbus_set_error(error, DBUS_ERROR_FAILED,
438 		               "%s: unknown element type %d", __func__, type);
439 		return FALSE;
440 	}
441 
442 	for (i = 0; i < array_len; i++) {
443 		if (!dbus_message_iter_append_basic(&array_iter, type,
444 						    array + i * element_size)) {
445 			dbus_set_error(error, DBUS_ERROR_FAILED,
446 				       "%s: failed to construct message 2.5",
447 				       __func__);
448 			return FALSE;
449 		}
450 	}
451 
452 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
453 		dbus_set_error(error, DBUS_ERROR_FAILED,
454 		               "%s: failed to construct message 3", __func__);
455 		return FALSE;
456 	}
457 
458 	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
459 		dbus_set_error(error, DBUS_ERROR_FAILED,
460 		               "%s: failed to construct message 4", __func__);
461 		return FALSE;
462 	}
463 
464 	return TRUE;
465 }
466 
467 
468 /**
469  * wpas_dbus_simple_array_array_property_getter - Get array array type property
470  * @iter: Pointer to incoming dbus message iterator
471  * @type: DBus type of property array elements (must be basic type)
472  * @array: pointer to array of elements to put into response message
473  * @array_len: length of above array
474  * @error: a pointer to an error to fill on failure
475  * Returns: TRUE if the request succeeded, FALSE if it failed
476  *
477  * Generic getter for array type properties. Array elements type is
478  * required to be basic.
479  */
wpas_dbus_simple_array_array_property_getter(DBusMessageIter * iter,const int type,struct wpabuf ** array,size_t array_len,DBusError * error)480 dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
481 							 const int type,
482 							 struct wpabuf **array,
483 							 size_t array_len,
484 							 DBusError *error)
485 {
486 	DBusMessageIter variant_iter, array_iter;
487 	char type_str[] = "aa?";
488 	char inner_type_str[] = "a?";
489 	const char *sub_type_str;
490 	size_t i;
491 
492 	if (!dbus_type_is_basic(type)) {
493 		dbus_set_error(error, DBUS_ERROR_FAILED,
494 			       "%s: given type is not basic", __func__);
495 		return FALSE;
496 	}
497 
498 	sub_type_str = wpa_dbus_type_as_string(type);
499 	type_str[2] = sub_type_str[0];
500 	inner_type_str[1] = sub_type_str[0];
501 
502 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
503 					      type_str, &variant_iter)) {
504 		dbus_set_error(error, DBUS_ERROR_FAILED,
505 			       "%s: failed to construct message 1", __func__);
506 		return FALSE;
507 	}
508 	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
509 					      inner_type_str, &array_iter)) {
510 		dbus_set_error(error, DBUS_ERROR_FAILED,
511 			       "%s: failed to construct message 2", __func__);
512 		return FALSE;
513 	}
514 
515 	for (i = 0; i < array_len && array[i]; i++) {
516 		wpa_dbus_dict_bin_array_add_element(&array_iter,
517 						    wpabuf_head(array[i]),
518 						    wpabuf_len(array[i]));
519 
520 	}
521 
522 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
523 		dbus_set_error(error, DBUS_ERROR_FAILED,
524 			       "%s: failed to close message 2", __func__);
525 		return FALSE;
526 	}
527 
528 	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
529 		dbus_set_error(error, DBUS_ERROR_FAILED,
530 			       "%s: failed to close message 1", __func__);
531 		return FALSE;
532 	}
533 
534 	return TRUE;
535 }
536 
537 
538 /**
539  * wpas_dbus_handler_create_interface - Request registration of a network iface
540  * @message: Pointer to incoming dbus message
541  * @global: %wpa_supplicant global data structure
542  * Returns: The object path of the new interface object,
543  *          or a dbus error message with more information
544  *
545  * Handler function for "CreateInterface" method call. Handles requests
546  * by dbus clients to register a network interface that wpa_supplicant
547  * will manage.
548  */
wpas_dbus_handler_create_interface(DBusMessage * message,struct wpa_global * global)549 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
550 						 struct wpa_global *global)
551 {
552 	DBusMessageIter iter_dict;
553 	DBusMessage *reply = NULL;
554 	DBusMessageIter iter;
555 	struct wpa_dbus_dict_entry entry;
556 	char *driver = NULL;
557 	char *ifname = NULL;
558 	char *confname = NULL;
559 	char *bridge_ifname = NULL;
560 
561 	dbus_message_iter_init(message, &iter);
562 
563 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
564 		goto error;
565 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
566 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
567 			goto error;
568 		if (!os_strcmp(entry.key, "Driver") &&
569 		    (entry.type == DBUS_TYPE_STRING)) {
570 			os_free(driver);
571 			driver = os_strdup(entry.str_value);
572 			wpa_dbus_dict_entry_clear(&entry);
573 			if (driver == NULL)
574 				goto error;
575 		} else if (!os_strcmp(entry.key, "Ifname") &&
576 			   (entry.type == DBUS_TYPE_STRING)) {
577 			os_free(ifname);
578 			ifname = os_strdup(entry.str_value);
579 			wpa_dbus_dict_entry_clear(&entry);
580 			if (ifname == NULL)
581 				goto error;
582 		} else if (!os_strcmp(entry.key, "ConfigFile") &&
583 			   (entry.type == DBUS_TYPE_STRING)) {
584 			os_free(confname);
585 			confname = os_strdup(entry.str_value);
586 			wpa_dbus_dict_entry_clear(&entry);
587 			if (confname == NULL)
588 				goto error;
589 		} else if (!os_strcmp(entry.key, "BridgeIfname") &&
590 			   (entry.type == DBUS_TYPE_STRING)) {
591 			os_free(bridge_ifname);
592 			bridge_ifname = os_strdup(entry.str_value);
593 			wpa_dbus_dict_entry_clear(&entry);
594 			if (bridge_ifname == NULL)
595 				goto error;
596 		} else {
597 			wpa_dbus_dict_entry_clear(&entry);
598 			goto error;
599 		}
600 	}
601 
602 	if (ifname == NULL)
603 		goto error; /* Required Ifname argument missing */
604 
605 	/*
606 	 * Try to get the wpa_supplicant record for this iface, return
607 	 * an error if we already control it.
608 	 */
609 	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
610 		reply = dbus_message_new_error(message,
611 					       WPAS_DBUS_ERROR_IFACE_EXISTS,
612 					       "wpa_supplicant already "
613 					       "controls this interface.");
614 	} else {
615 		struct wpa_supplicant *wpa_s;
616 		struct wpa_interface iface;
617 		os_memset(&iface, 0, sizeof(iface));
618 		iface.driver = driver;
619 		iface.ifname = ifname;
620 		iface.confname = confname;
621 		iface.bridge_ifname = bridge_ifname;
622 		/* Otherwise, have wpa_supplicant attach to it. */
623 		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
624 			const char *path = wpa_s->dbus_new_path;
625 			reply = dbus_message_new_method_return(message);
626 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
627 			                         &path, DBUS_TYPE_INVALID);
628 		} else {
629 			reply = wpas_dbus_error_unknown_error(
630 				message, "wpa_supplicant couldn't grab this "
631 				"interface.");
632 		}
633 	}
634 
635 out:
636 	os_free(driver);
637 	os_free(ifname);
638 	os_free(confname);
639 	os_free(bridge_ifname);
640 	return reply;
641 
642 error:
643 	reply = wpas_dbus_error_invalid_args(message, NULL);
644 	goto out;
645 }
646 
647 
648 /**
649  * wpas_dbus_handler_remove_interface - Request deregistration of an interface
650  * @message: Pointer to incoming dbus message
651  * @global: wpa_supplicant global data structure
652  * Returns: a dbus message containing a UINT32 indicating success (1) or
653  *          failure (0), or returns a dbus error message with more information
654  *
655  * Handler function for "removeInterface" method call.  Handles requests
656  * by dbus clients to deregister a network interface that wpa_supplicant
657  * currently manages.
658  */
wpas_dbus_handler_remove_interface(DBusMessage * message,struct wpa_global * global)659 DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
660 						 struct wpa_global *global)
661 {
662 	struct wpa_supplicant *wpa_s;
663 	char *path;
664 	DBusMessage *reply = NULL;
665 
666 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
667 			      DBUS_TYPE_INVALID);
668 
669 	wpa_s = get_iface_by_dbus_path(global, path);
670 	if (wpa_s == NULL)
671 		reply = wpas_dbus_error_iface_unknown(message);
672 	else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
673 		reply = wpas_dbus_error_unknown_error(
674 			message, "wpa_supplicant couldn't remove this "
675 			"interface.");
676 	}
677 
678 	return reply;
679 }
680 
681 
682 /**
683  * wpas_dbus_handler_get_interface - Get the object path for an interface name
684  * @message: Pointer to incoming dbus message
685  * @global: %wpa_supplicant global data structure
686  * Returns: The object path of the interface object,
687  *          or a dbus error message with more information
688  *
689  * Handler function for "getInterface" method call.
690  */
wpas_dbus_handler_get_interface(DBusMessage * message,struct wpa_global * global)691 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
692 					      struct wpa_global *global)
693 {
694 	DBusMessage *reply = NULL;
695 	const char *ifname;
696 	const char *path;
697 	struct wpa_supplicant *wpa_s;
698 
699 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
700 			      DBUS_TYPE_INVALID);
701 
702 	wpa_s = wpa_supplicant_get_iface(global, ifname);
703 	if (wpa_s == NULL)
704 		return wpas_dbus_error_iface_unknown(message);
705 
706 	path = wpa_s->dbus_new_path;
707 	reply = dbus_message_new_method_return(message);
708 	if (reply == NULL)
709 		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
710 					      NULL);
711 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
712 				      DBUS_TYPE_INVALID)) {
713 		dbus_message_unref(reply);
714 		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
715 					      NULL);
716 	}
717 
718 	return reply;
719 }
720 
721 
722 /**
723  * wpas_dbus_getter_debug_level - Get debug level
724  * @iter: Pointer to incoming dbus message iter
725  * @error: Location to store error on failure
726  * @user_data: Function specific data
727  * Returns: TRUE on success, FALSE on failure
728  *
729  * Getter for "DebugLevel" property.
730  */
wpas_dbus_getter_debug_level(DBusMessageIter * iter,DBusError * error,void * user_data)731 dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
732 					 DBusError *error,
733 					 void *user_data)
734 {
735 	const char *str;
736 	int idx = wpa_debug_level;
737 
738 	if (idx < 0)
739 		idx = 0;
740 	if (idx > 5)
741 		idx = 5;
742 	str = debug_strings[idx];
743 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
744 						&str, error);
745 }
746 
747 
748 /**
749  * wpas_dbus_getter_debug_timestamp - Get debug timestamp
750  * @iter: Pointer to incoming dbus message iter
751  * @error: Location to store error on failure
752  * @user_data: Function specific data
753  * Returns: TRUE on success, FALSE on failure
754  *
755  * Getter for "DebugTimestamp" property.
756  */
wpas_dbus_getter_debug_timestamp(DBusMessageIter * iter,DBusError * error,void * user_data)757 dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
758                                              DBusError *error,
759                                              void *user_data)
760 {
761 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
762 						&wpa_debug_timestamp, error);
763 
764 }
765 
766 
767 /**
768  * wpas_dbus_getter_debug_show_keys - Get debug show keys
769  * @iter: Pointer to incoming dbus message iter
770  * @error: Location to store error on failure
771  * @user_data: Function specific data
772  * Returns: TRUE on success, FALSE on failure
773  *
774  * Getter for "DebugShowKeys" property.
775  */
wpas_dbus_getter_debug_show_keys(DBusMessageIter * iter,DBusError * error,void * user_data)776 dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
777 					     DBusError *error,
778 					     void *user_data)
779 {
780 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
781 						&wpa_debug_show_keys, error);
782 
783 }
784 
785 /**
786  * wpas_dbus_setter_debug_level - Set debug level
787  * @iter: Pointer to incoming dbus message iter
788  * @error: Location to store error on failure
789  * @user_data: Function specific data
790  * Returns: TRUE on success, FALSE on failure
791  *
792  * Setter for "DebugLevel" property.
793  */
wpas_dbus_setter_debug_level(DBusMessageIter * iter,DBusError * error,void * user_data)794 dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
795 					 DBusError *error, void *user_data)
796 {
797 	struct wpa_global *global = user_data;
798 	const char *str = NULL;
799 	int i, val = -1;
800 
801 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
802 					      &str))
803 		return FALSE;
804 
805 	for (i = 0; debug_strings[i]; i++)
806 		if (os_strcmp(debug_strings[i], str) == 0) {
807 			val = i;
808 			break;
809 		}
810 
811 	if (val < 0 ||
812 	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
813 					    wpa_debug_show_keys)) {
814 		dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
815 				     "level value");
816 		return FALSE;
817 	}
818 
819 	return TRUE;
820 }
821 
822 
823 /**
824  * wpas_dbus_setter_debug_timestamp - Set debug timestamp
825  * @iter: Pointer to incoming dbus message iter
826  * @error: Location to store error on failure
827  * @user_data: Function specific data
828  * Returns: TRUE on success, FALSE on failure
829  *
830  * Setter for "DebugTimestamp" property.
831  */
wpas_dbus_setter_debug_timestamp(DBusMessageIter * iter,DBusError * error,void * user_data)832 dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
833 					     DBusError *error,
834 					     void *user_data)
835 {
836 	struct wpa_global *global = user_data;
837 	dbus_bool_t val;
838 
839 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
840 					      &val))
841 		return FALSE;
842 
843 	wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
844 					wpa_debug_show_keys);
845 	return TRUE;
846 }
847 
848 
849 /**
850  * wpas_dbus_setter_debug_show_keys - Set debug show keys
851  * @iter: Pointer to incoming dbus message iter
852  * @error: Location to store error on failure
853  * @user_data: Function specific data
854  * Returns: TRUE on success, FALSE on failure
855  *
856  * Setter for "DebugShowKeys" property.
857  */
wpas_dbus_setter_debug_show_keys(DBusMessageIter * iter,DBusError * error,void * user_data)858 dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
859 					     DBusError *error,
860 					     void *user_data)
861 {
862 	struct wpa_global *global = user_data;
863 	dbus_bool_t val;
864 
865 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
866 					      &val))
867 		return FALSE;
868 
869 	wpa_supplicant_set_debug_params(global, wpa_debug_level,
870 					wpa_debug_timestamp,
871 					val ? 1 : 0);
872 	return TRUE;
873 }
874 
875 
876 /**
877  * wpas_dbus_getter_interfaces - Request registered interfaces list
878  * @iter: Pointer to incoming dbus message iter
879  * @error: Location to store error on failure
880  * @user_data: Function specific data
881  * Returns: TRUE on success, FALSE on failure
882  *
883  * Getter for "Interfaces" property. Handles requests
884  * by dbus clients to return list of registered interfaces objects
885  * paths
886  */
wpas_dbus_getter_interfaces(DBusMessageIter * iter,DBusError * error,void * user_data)887 dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
888 					DBusError *error,
889 					void *user_data)
890 {
891 	struct wpa_global *global = user_data;
892 	struct wpa_supplicant *wpa_s;
893 	const char **paths;
894 	unsigned int i = 0, num = 0;
895 	dbus_bool_t success;
896 
897 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
898 		num++;
899 
900 	paths = os_calloc(num, sizeof(char *));
901 	if (!paths) {
902 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
903 		return FALSE;
904 	}
905 
906 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
907 		paths[i++] = wpa_s->dbus_new_path;
908 
909 	success = wpas_dbus_simple_array_property_getter(iter,
910 							 DBUS_TYPE_OBJECT_PATH,
911 							 paths, num, error);
912 
913 	os_free(paths);
914 	return success;
915 }
916 
917 
918 /**
919  * wpas_dbus_getter_eap_methods - Request supported EAP methods list
920  * @iter: Pointer to incoming dbus message iter
921  * @error: Location to store error on failure
922  * @user_data: Function specific data
923  * Returns: TRUE on success, FALSE on failure
924  *
925  * Getter for "EapMethods" property. Handles requests
926  * by dbus clients to return list of strings with supported EAP methods
927  */
wpas_dbus_getter_eap_methods(DBusMessageIter * iter,DBusError * error,void * user_data)928 dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
929 					 DBusError *error, void *user_data)
930 {
931 	char **eap_methods;
932 	size_t num_items = 0;
933 	dbus_bool_t success;
934 
935 	eap_methods = eap_get_names_as_string_array(&num_items);
936 	if (!eap_methods) {
937 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
938 		return FALSE;
939 	}
940 
941 	success = wpas_dbus_simple_array_property_getter(iter,
942 							 DBUS_TYPE_STRING,
943 							 eap_methods,
944 							 num_items, error);
945 
946 	while (num_items)
947 		os_free(eap_methods[--num_items]);
948 	os_free(eap_methods);
949 	return success;
950 }
951 
952 
953 /**
954  * wpas_dbus_getter_global_capabilities - Request supported global capabilities
955  * @iter: Pointer to incoming dbus message iter
956  * @error: Location to store error on failure
957  * @user_data: Function specific data
958  * Returns: TRUE on success, FALSE on failure
959  *
960  * Getter for "Capabilities" property. Handles requests by dbus clients to
961  * return a list of strings with supported capabilities like AP, RSN IBSS,
962  * and P2P that are determined at compile time.
963  */
wpas_dbus_getter_global_capabilities(DBusMessageIter * iter,DBusError * error,void * user_data)964 dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
965 					         DBusError *error,
966 					         void *user_data)
967 {
968 	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
969 	size_t num_items = 0;
970 
971 #ifdef CONFIG_AP
972 	capabilities[num_items++] = "ap";
973 #endif /* CONFIG_AP */
974 #ifdef CONFIG_IBSS_RSN
975 	capabilities[num_items++] = "ibss-rsn";
976 #endif /* CONFIG_IBSS_RSN */
977 #ifdef CONFIG_P2P
978 	capabilities[num_items++] = "p2p";
979 #endif /* CONFIG_P2P */
980 #ifdef CONFIG_INTERWORKING
981 	capabilities[num_items++] = "interworking";
982 #endif /* CONFIG_INTERWORKING */
983 
984 	return wpas_dbus_simple_array_property_getter(iter,
985 						      DBUS_TYPE_STRING,
986 						      capabilities,
987 						      num_items, error);
988 }
989 
990 
wpas_dbus_get_scan_type(DBusMessage * message,DBusMessageIter * var,char ** type,DBusMessage ** reply)991 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
992 				   char **type, DBusMessage **reply)
993 {
994 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
995 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
996 			   "Type must be a string");
997 		*reply = wpas_dbus_error_invalid_args(
998 			message, "Wrong Type value type. String required");
999 		return -1;
1000 	}
1001 	dbus_message_iter_get_basic(var, type);
1002 	return 0;
1003 }
1004 
1005 
wpas_dbus_get_scan_ssids(DBusMessage * message,DBusMessageIter * var,struct wpa_driver_scan_params * params,DBusMessage ** reply)1006 static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
1007 				    struct wpa_driver_scan_params *params,
1008 				    DBusMessage **reply)
1009 {
1010 	struct wpa_driver_scan_ssid *ssids = params->ssids;
1011 	size_t ssids_num = 0;
1012 	u8 *ssid;
1013 	DBusMessageIter array_iter, sub_array_iter;
1014 	char *val;
1015 	int len;
1016 
1017 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1018 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
1019 			   "must be an array of arrays of bytes");
1020 		*reply = wpas_dbus_error_invalid_args(
1021 			message, "Wrong SSIDs value type. Array of arrays of "
1022 			"bytes required");
1023 		return -1;
1024 	}
1025 
1026 	dbus_message_iter_recurse(var, &array_iter);
1027 
1028 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1029 	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
1030 	{
1031 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
1032 			   "must be an array of arrays of bytes");
1033 		*reply = wpas_dbus_error_invalid_args(
1034 			message, "Wrong SSIDs value type. Array of arrays of "
1035 			"bytes required");
1036 		return -1;
1037 	}
1038 
1039 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
1040 	{
1041 		if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
1042 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1043 				   "Too many ssids specified on scan dbus "
1044 				   "call");
1045 			*reply = wpas_dbus_error_invalid_args(
1046 				message, "Too many ssids specified. Specify "
1047 				"at most four");
1048 			return -1;
1049 		}
1050 
1051 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1052 
1053 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1054 
1055 		if (len > MAX_SSID_LEN) {
1056 			wpa_printf(MSG_DEBUG,
1057 				   "wpas_dbus_handler_scan[dbus]: "
1058 				   "SSID too long (len=%d max_len=%d)",
1059 				   len, MAX_SSID_LEN);
1060 			*reply = wpas_dbus_error_invalid_args(
1061 				message, "Invalid SSID: too long");
1062 			return -1;
1063 		}
1064 
1065 		if (len != 0) {
1066 			ssid = os_malloc(len);
1067 			if (ssid == NULL) {
1068 				wpa_printf(MSG_DEBUG,
1069 					   "wpas_dbus_handler_scan[dbus]: "
1070 					   "out of memory. Cannot allocate "
1071 					   "memory for SSID");
1072 				*reply = dbus_message_new_error(
1073 					message, DBUS_ERROR_NO_MEMORY, NULL);
1074 				return -1;
1075 			}
1076 			os_memcpy(ssid, val, len);
1077 		} else {
1078 			/* Allow zero-length SSIDs */
1079 			ssid = NULL;
1080 		}
1081 
1082 		ssids[ssids_num].ssid = ssid;
1083 		ssids[ssids_num].ssid_len = len;
1084 
1085 		dbus_message_iter_next(&array_iter);
1086 		ssids_num++;
1087 	}
1088 
1089 	params->num_ssids = ssids_num;
1090 	return 0;
1091 }
1092 
1093 
wpas_dbus_get_scan_ies(DBusMessage * message,DBusMessageIter * var,struct wpa_driver_scan_params * params,DBusMessage ** reply)1094 static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
1095 				  struct wpa_driver_scan_params *params,
1096 				  DBusMessage **reply)
1097 {
1098 	u8 *ies = NULL, *nies;
1099 	int ies_len = 0;
1100 	DBusMessageIter array_iter, sub_array_iter;
1101 	char *val;
1102 	int len;
1103 
1104 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1105 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
1106 			   "be an array of arrays of bytes");
1107 		*reply = wpas_dbus_error_invalid_args(
1108 			message, "Wrong IEs value type. Array of arrays of "
1109 			"bytes required");
1110 		return -1;
1111 	}
1112 
1113 	dbus_message_iter_recurse(var, &array_iter);
1114 
1115 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1116 	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
1117 	{
1118 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
1119 			   "be an array of arrays of bytes");
1120 		*reply = wpas_dbus_error_invalid_args(
1121 			message, "Wrong IEs value type. Array required");
1122 		return -1;
1123 	}
1124 
1125 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
1126 	{
1127 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1128 
1129 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1130 		if (len == 0) {
1131 			dbus_message_iter_next(&array_iter);
1132 			continue;
1133 		}
1134 
1135 		nies = os_realloc(ies, ies_len + len);
1136 		if (nies == NULL) {
1137 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1138 				   "out of memory. Cannot allocate memory for "
1139 				   "IE");
1140 			os_free(ies);
1141 			*reply = dbus_message_new_error(
1142 				message, DBUS_ERROR_NO_MEMORY, NULL);
1143 			return -1;
1144 		}
1145 		ies = nies;
1146 		os_memcpy(ies + ies_len, val, len);
1147 		ies_len += len;
1148 
1149 		dbus_message_iter_next(&array_iter);
1150 	}
1151 
1152 	params->extra_ies = ies;
1153 	params->extra_ies_len = ies_len;
1154 	return 0;
1155 }
1156 
1157 
wpas_dbus_get_scan_channels(DBusMessage * message,DBusMessageIter * var,struct wpa_driver_scan_params * params,DBusMessage ** reply)1158 static int wpas_dbus_get_scan_channels(DBusMessage *message,
1159 				       DBusMessageIter *var,
1160 				       struct wpa_driver_scan_params *params,
1161 				       DBusMessage **reply)
1162 {
1163 	DBusMessageIter array_iter, sub_array_iter;
1164 	int *freqs = NULL, *nfreqs;
1165 	int freqs_num = 0;
1166 
1167 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1168 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1169 			   "Channels must be an array of structs");
1170 		*reply = wpas_dbus_error_invalid_args(
1171 			message, "Wrong Channels value type. Array of structs "
1172 			"required");
1173 		return -1;
1174 	}
1175 
1176 	dbus_message_iter_recurse(var, &array_iter);
1177 
1178 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
1179 		wpa_printf(MSG_DEBUG,
1180 			   "wpas_dbus_handler_scan[dbus]: Channels must be an "
1181 			   "array of structs");
1182 		*reply = wpas_dbus_error_invalid_args(
1183 			message, "Wrong Channels value type. Array of structs "
1184 			"required");
1185 		return -1;
1186 	}
1187 
1188 	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
1189 	{
1190 		int freq, width;
1191 
1192 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1193 
1194 		if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
1195 		    DBUS_TYPE_UINT32) {
1196 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1197 				   "Channel must by specified by struct of "
1198 				   "two UINT32s %c",
1199 				   dbus_message_iter_get_arg_type(
1200 					   &sub_array_iter));
1201 			*reply = wpas_dbus_error_invalid_args(
1202 				message, "Wrong Channel struct. Two UINT32s "
1203 				"required");
1204 			os_free(freqs);
1205 			return -1;
1206 		}
1207 		dbus_message_iter_get_basic(&sub_array_iter, &freq);
1208 
1209 		if (!dbus_message_iter_next(&sub_array_iter) ||
1210 		    dbus_message_iter_get_arg_type(&sub_array_iter) !=
1211 		    DBUS_TYPE_UINT32) {
1212 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1213 				   "Channel must by specified by struct of "
1214 				   "two UINT32s");
1215 			*reply = wpas_dbus_error_invalid_args(
1216 				message,
1217 				"Wrong Channel struct. Two UINT32s required");
1218 			os_free(freqs);
1219 			return -1;
1220 		}
1221 
1222 		dbus_message_iter_get_basic(&sub_array_iter, &width);
1223 
1224 #define FREQS_ALLOC_CHUNK 32
1225 		if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
1226 			nfreqs = os_realloc_array(
1227 				freqs, freqs_num + FREQS_ALLOC_CHUNK,
1228 				sizeof(int));
1229 			if (nfreqs == NULL)
1230 				os_free(freqs);
1231 			freqs = nfreqs;
1232 		}
1233 		if (freqs == NULL) {
1234 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1235 				   "out of memory. can't allocate memory for "
1236 				   "freqs");
1237 			*reply = dbus_message_new_error(
1238 				message, DBUS_ERROR_NO_MEMORY, NULL);
1239 			return -1;
1240 		}
1241 
1242 		freqs[freqs_num] = freq;
1243 
1244 		freqs_num++;
1245 		dbus_message_iter_next(&array_iter);
1246 	}
1247 
1248 	nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
1249 	if (nfreqs == NULL)
1250 		os_free(freqs);
1251 	freqs = nfreqs;
1252 	if (freqs == NULL) {
1253 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1254 			   "out of memory. Can't allocate memory for freqs");
1255 		*reply = dbus_message_new_error(
1256 			message, DBUS_ERROR_NO_MEMORY, NULL);
1257 		return -1;
1258 	}
1259 	freqs[freqs_num] = 0;
1260 
1261 	params->freqs = freqs;
1262 	return 0;
1263 }
1264 
1265 
wpas_dbus_get_scan_allow_roam(DBusMessage * message,DBusMessageIter * var,dbus_bool_t * allow,DBusMessage ** reply)1266 static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
1267 					 DBusMessageIter *var,
1268 					 dbus_bool_t *allow,
1269 					 DBusMessage **reply)
1270 {
1271 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
1272 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1273 			   "Type must be a boolean");
1274 		*reply = wpas_dbus_error_invalid_args(
1275 			message, "Wrong Type value type. Boolean required");
1276 		return -1;
1277 	}
1278 	dbus_message_iter_get_basic(var, allow);
1279 	return 0;
1280 }
1281 
1282 
1283 /**
1284  * wpas_dbus_handler_scan - Request a wireless scan on an interface
1285  * @message: Pointer to incoming dbus message
1286  * @wpa_s: wpa_supplicant structure for a network interface
1287  * Returns: NULL indicating success or DBus error message on failure
1288  *
1289  * Handler function for "Scan" method call of a network device. Requests
1290  * that wpa_supplicant perform a wireless scan as soon as possible
1291  * on a particular wireless interface.
1292  */
wpas_dbus_handler_scan(DBusMessage * message,struct wpa_supplicant * wpa_s)1293 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
1294 				     struct wpa_supplicant *wpa_s)
1295 {
1296 	DBusMessage *reply = NULL;
1297 	DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
1298 	char *key = NULL, *type = NULL;
1299 	struct wpa_driver_scan_params params;
1300 	size_t i;
1301 	dbus_bool_t allow_roam = 1;
1302 
1303 	os_memset(&params, 0, sizeof(params));
1304 
1305 	dbus_message_iter_init(message, &iter);
1306 
1307 	dbus_message_iter_recurse(&iter, &dict_iter);
1308 
1309 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
1310 			DBUS_TYPE_DICT_ENTRY) {
1311 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
1312 		dbus_message_iter_get_basic(&entry_iter, &key);
1313 		dbus_message_iter_next(&entry_iter);
1314 		dbus_message_iter_recurse(&entry_iter, &variant_iter);
1315 
1316 		if (os_strcmp(key, "Type") == 0) {
1317 			if (wpas_dbus_get_scan_type(message, &variant_iter,
1318 						    &type, &reply) < 0)
1319 				goto out;
1320 		} else if (os_strcmp(key, "SSIDs") == 0) {
1321 			if (wpas_dbus_get_scan_ssids(message, &variant_iter,
1322 						     &params, &reply) < 0)
1323 				goto out;
1324 		} else if (os_strcmp(key, "IEs") == 0) {
1325 			if (wpas_dbus_get_scan_ies(message, &variant_iter,
1326 						   &params, &reply) < 0)
1327 				goto out;
1328 		} else if (os_strcmp(key, "Channels") == 0) {
1329 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
1330 							&params, &reply) < 0)
1331 				goto out;
1332 		} else if (os_strcmp(key, "AllowRoam") == 0) {
1333 			if (wpas_dbus_get_scan_allow_roam(message,
1334 							  &variant_iter,
1335 							  &allow_roam,
1336 							  &reply) < 0)
1337 				goto out;
1338 		} else {
1339 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1340 				   "Unknown argument %s", key);
1341 			reply = wpas_dbus_error_invalid_args(message, key);
1342 			goto out;
1343 		}
1344 
1345 		dbus_message_iter_next(&dict_iter);
1346 	}
1347 
1348 	if (!type) {
1349 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1350 			   "Scan type not specified");
1351 		reply = wpas_dbus_error_invalid_args(message, key);
1352 		goto out;
1353 	}
1354 
1355 	if (!os_strcmp(type, "passive")) {
1356 		if (params.num_ssids || params.extra_ies_len) {
1357 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1358 				   "SSIDs or IEs specified for passive scan.");
1359 			reply = wpas_dbus_error_invalid_args(
1360 				message, "You can specify only Channels in "
1361 				"passive scan");
1362 			goto out;
1363 		} else if (params.freqs && params.freqs[0]) {
1364 			if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1365 				reply = wpas_dbus_error_scan_error(
1366 					message, "Scan request rejected");
1367 			}
1368 		} else {
1369 			wpa_s->scan_req = MANUAL_SCAN_REQ;
1370 			wpa_supplicant_req_scan(wpa_s, 0, 0);
1371 		}
1372 	} else if (!os_strcmp(type, "active")) {
1373 		if (!params.num_ssids) {
1374 			/* Add wildcard ssid */
1375 			params.num_ssids++;
1376 		}
1377 #ifdef CONFIG_AUTOSCAN
1378 		autoscan_deinit(wpa_s);
1379 #endif /* CONFIG_AUTOSCAN */
1380 		if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1381 			reply = wpas_dbus_error_scan_error(
1382 				message, "Scan request rejected");
1383 		}
1384 	} else {
1385 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1386 			   "Unknown scan type: %s", type);
1387 		reply = wpas_dbus_error_invalid_args(message,
1388 						     "Wrong scan type");
1389 		goto out;
1390 	}
1391 
1392 	if (!allow_roam)
1393 		wpa_s->scan_res_handler = scan_only_handler;
1394 
1395 out:
1396 	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
1397 		os_free((u8 *) params.ssids[i].ssid);
1398 	os_free((u8 *) params.extra_ies);
1399 	os_free(params.freqs);
1400 	return reply;
1401 }
1402 
1403 
1404 /*
1405  * wpas_dbus_handler_disconnect - Terminate the current connection
1406  * @message: Pointer to incoming dbus message
1407  * @wpa_s: wpa_supplicant structure for a network interface
1408  * Returns: NotConnected DBus error message if already not connected
1409  * or NULL otherwise.
1410  *
1411  * Handler function for "Disconnect" method call of network interface.
1412  */
wpas_dbus_handler_disconnect(DBusMessage * message,struct wpa_supplicant * wpa_s)1413 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
1414 					   struct wpa_supplicant *wpa_s)
1415 {
1416 	if (wpa_s->current_ssid != NULL) {
1417 		wpa_s->disconnected = 1;
1418 		wpa_supplicant_deauthenticate(wpa_s,
1419 					      WLAN_REASON_DEAUTH_LEAVING);
1420 
1421 		return NULL;
1422 	}
1423 
1424 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1425 				      "This interface is not connected");
1426 }
1427 
1428 
1429 /**
1430  * wpas_dbus_new_iface_add_network - Add a new configured network
1431  * @message: Pointer to incoming dbus message
1432  * @wpa_s: wpa_supplicant structure for a network interface
1433  * Returns: A dbus message containing the object path of the new network
1434  *
1435  * Handler function for "AddNetwork" method call of a network interface.
1436  */
wpas_dbus_handler_add_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1437 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
1438 					    struct wpa_supplicant *wpa_s)
1439 {
1440 	DBusMessage *reply = NULL;
1441 	DBusMessageIter	iter;
1442 	struct wpa_ssid *ssid = NULL;
1443 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1444 	DBusError error;
1445 
1446 	dbus_message_iter_init(message, &iter);
1447 
1448 	ssid = wpa_config_add_network(wpa_s->conf);
1449 	if (ssid == NULL) {
1450 		wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
1451 			   "can't add new interface.");
1452 		reply = wpas_dbus_error_unknown_error(
1453 			message,
1454 			"wpa_supplicant could not add "
1455 			"a network on this interface.");
1456 		goto err;
1457 	}
1458 	wpas_notify_network_added(wpa_s, ssid);
1459 	ssid->disabled = 1;
1460 	wpa_config_set_network_defaults(ssid);
1461 
1462 	dbus_error_init(&error);
1463 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1464 		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
1465 			   "control interface couldn't set network "
1466 			   "properties");
1467 		reply = wpas_dbus_reply_new_from_error(message, &error,
1468 						       DBUS_ERROR_INVALID_ARGS,
1469 						       "Failed to add network");
1470 		dbus_error_free(&error);
1471 		goto err;
1472 	}
1473 
1474 	/* Construct the object path for this network. */
1475 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1476 		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
1477 		    wpa_s->dbus_new_path, ssid->id);
1478 
1479 	reply = dbus_message_new_method_return(message);
1480 	if (reply == NULL) {
1481 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1482 					       NULL);
1483 		goto err;
1484 	}
1485 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1486 				      DBUS_TYPE_INVALID)) {
1487 		dbus_message_unref(reply);
1488 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1489 					       NULL);
1490 		goto err;
1491 	}
1492 
1493 	return reply;
1494 
1495 err:
1496 	if (ssid) {
1497 		wpas_notify_network_removed(wpa_s, ssid);
1498 		wpa_config_remove_network(wpa_s->conf, ssid->id);
1499 	}
1500 	return reply;
1501 }
1502 
1503 
1504 /**
1505  * wpas_dbus_handler_reassociate - Reassociate
1506  * @message: Pointer to incoming dbus message
1507  * @wpa_s: wpa_supplicant structure for a network interface
1508  * Returns: InterfaceDisabled DBus error message if disabled
1509  * or NULL otherwise.
1510  *
1511  * Handler function for "Reassociate" method call of network interface.
1512  */
wpas_dbus_handler_reassociate(DBusMessage * message,struct wpa_supplicant * wpa_s)1513 DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
1514 					    struct wpa_supplicant *wpa_s)
1515 {
1516 	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
1517 		wpas_request_connection(wpa_s);
1518 		return NULL;
1519 	}
1520 
1521 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
1522 				      "This interface is disabled");
1523 }
1524 
1525 
1526 /**
1527  * wpas_dbus_handler_reattach - Reattach to current AP
1528  * @message: Pointer to incoming dbus message
1529  * @wpa_s: wpa_supplicant structure for a network interface
1530  * Returns: NotConnected DBus error message if not connected
1531  * or NULL otherwise.
1532  *
1533  * Handler function for "Reattach" method call of network interface.
1534  */
wpas_dbus_handler_reattach(DBusMessage * message,struct wpa_supplicant * wpa_s)1535 DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
1536 					 struct wpa_supplicant *wpa_s)
1537 {
1538 	if (wpa_s->current_ssid != NULL) {
1539 		wpa_s->reattach = 1;
1540 		wpas_request_connection(wpa_s);
1541 		return NULL;
1542 	}
1543 
1544 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1545 				      "This interface is not connected");
1546 }
1547 
1548 
1549 /**
1550  * wpas_dbus_handler_remove_network - Remove a configured network
1551  * @message: Pointer to incoming dbus message
1552  * @wpa_s: wpa_supplicant structure for a network interface
1553  * Returns: NULL on success or dbus error on failure
1554  *
1555  * Handler function for "RemoveNetwork" method call of a network interface.
1556  */
wpas_dbus_handler_remove_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1557 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
1558 					       struct wpa_supplicant *wpa_s)
1559 {
1560 	DBusMessage *reply = NULL;
1561 	const char *op;
1562 	char *iface = NULL, *net_id = NULL;
1563 	int id;
1564 	struct wpa_ssid *ssid;
1565 	int was_disabled;
1566 
1567 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1568 			      DBUS_TYPE_INVALID);
1569 
1570 	/* Extract the network ID and ensure the network */
1571 	/* is actually a child of this interface */
1572 	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
1573 	if (iface == NULL || net_id == NULL ||
1574 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1575 		reply = wpas_dbus_error_invalid_args(message, op);
1576 		goto out;
1577 	}
1578 
1579 	errno = 0;
1580 	id = strtoul(net_id, NULL, 10);
1581 	if (errno != 0) {
1582 		reply = wpas_dbus_error_invalid_args(message, op);
1583 		goto out;
1584 	}
1585 
1586 	ssid = wpa_config_get_network(wpa_s->conf, id);
1587 	if (ssid == NULL) {
1588 		reply = wpas_dbus_error_network_unknown(message);
1589 		goto out;
1590 	}
1591 
1592 	was_disabled = ssid->disabled;
1593 
1594 	wpas_notify_network_removed(wpa_s, ssid);
1595 
1596 	if (ssid == wpa_s->current_ssid)
1597 		wpa_supplicant_deauthenticate(wpa_s,
1598 					      WLAN_REASON_DEAUTH_LEAVING);
1599 	else if (!was_disabled && wpa_s->sched_scanning) {
1600 		wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
1601 			   "network from filters");
1602 		wpa_supplicant_cancel_sched_scan(wpa_s);
1603 		wpa_supplicant_req_scan(wpa_s, 0, 0);
1604 	}
1605 
1606 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1607 		wpa_printf(MSG_ERROR,
1608 			   "wpas_dbus_handler_remove_network[dbus]: "
1609 			   "error occurred when removing network %d", id);
1610 		reply = wpas_dbus_error_unknown_error(
1611 			message, "error removing the specified network on "
1612 			"this interface.");
1613 		goto out;
1614 	}
1615 
1616 out:
1617 	os_free(iface);
1618 	os_free(net_id);
1619 	return reply;
1620 }
1621 
1622 
remove_network(void * arg,struct wpa_ssid * ssid)1623 static void remove_network(void *arg, struct wpa_ssid *ssid)
1624 {
1625 	struct wpa_supplicant *wpa_s = arg;
1626 
1627 	wpas_notify_network_removed(wpa_s, ssid);
1628 
1629 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1630 		wpa_printf(MSG_ERROR,
1631 			   "wpas_dbus_handler_remove_all_networks[dbus]: "
1632 			   "error occurred when removing network %d",
1633 			   ssid->id);
1634 		return;
1635 	}
1636 
1637 	if (ssid == wpa_s->current_ssid)
1638 		wpa_supplicant_deauthenticate(wpa_s,
1639 					      WLAN_REASON_DEAUTH_LEAVING);
1640 }
1641 
1642 
1643 /**
1644  * wpas_dbus_handler_remove_all_networks - Remove all configured networks
1645  * @message: Pointer to incoming dbus message
1646  * @wpa_s: wpa_supplicant structure for a network interface
1647  * Returns: NULL on success or dbus error on failure
1648  *
1649  * Handler function for "RemoveAllNetworks" method call of a network interface.
1650  */
wpas_dbus_handler_remove_all_networks(DBusMessage * message,struct wpa_supplicant * wpa_s)1651 DBusMessage * wpas_dbus_handler_remove_all_networks(
1652 	DBusMessage *message, struct wpa_supplicant *wpa_s)
1653 {
1654 	if (wpa_s->sched_scanning)
1655 		wpa_supplicant_cancel_sched_scan(wpa_s);
1656 
1657 	/* NB: could check for failure and return an error */
1658 	wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
1659 	return NULL;
1660 }
1661 
1662 
1663 /**
1664  * wpas_dbus_handler_select_network - Attempt association with a network
1665  * @message: Pointer to incoming dbus message
1666  * @wpa_s: wpa_supplicant structure for a network interface
1667  * Returns: NULL on success or dbus error on failure
1668  *
1669  * Handler function for "SelectNetwork" method call of network interface.
1670  */
wpas_dbus_handler_select_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1671 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
1672 					       struct wpa_supplicant *wpa_s)
1673 {
1674 	DBusMessage *reply = NULL;
1675 	const char *op;
1676 	char *iface = NULL, *net_id = NULL;
1677 	int id;
1678 	struct wpa_ssid *ssid;
1679 
1680 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1681 			      DBUS_TYPE_INVALID);
1682 
1683 	/* Extract the network ID and ensure the network */
1684 	/* is actually a child of this interface */
1685 	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
1686 	if (iface == NULL || net_id == NULL ||
1687 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1688 		reply = wpas_dbus_error_invalid_args(message, op);
1689 		goto out;
1690 	}
1691 
1692 	errno = 0;
1693 	id = strtoul(net_id, NULL, 10);
1694 	if (errno != 0) {
1695 		reply = wpas_dbus_error_invalid_args(message, op);
1696 		goto out;
1697 	}
1698 
1699 	ssid = wpa_config_get_network(wpa_s->conf, id);
1700 	if (ssid == NULL) {
1701 		reply = wpas_dbus_error_network_unknown(message);
1702 		goto out;
1703 	}
1704 
1705 	/* Finally, associate with the network */
1706 	wpa_supplicant_select_network(wpa_s, ssid);
1707 
1708 out:
1709 	os_free(iface);
1710 	os_free(net_id);
1711 	return reply;
1712 }
1713 
1714 
1715 /**
1716  * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
1717  * @message: Pointer to incoming dbus message
1718  * @wpa_s: wpa_supplicant structure for a network interface
1719  * Returns: NULL on success or dbus error on failure
1720  *
1721  * Handler function for "NetworkReply" method call of network interface.
1722  */
wpas_dbus_handler_network_reply(DBusMessage * message,struct wpa_supplicant * wpa_s)1723 DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
1724 					      struct wpa_supplicant *wpa_s)
1725 {
1726 #ifdef IEEE8021X_EAPOL
1727 	DBusMessage *reply = NULL;
1728 	const char *op, *field, *value;
1729 	char *iface = NULL, *net_id = NULL;
1730 	int id;
1731 	struct wpa_ssid *ssid;
1732 
1733 	if (!dbus_message_get_args(message, NULL,
1734 	                           DBUS_TYPE_OBJECT_PATH, &op,
1735 	                           DBUS_TYPE_STRING, &field,
1736 	                           DBUS_TYPE_STRING, &value,
1737 			           DBUS_TYPE_INVALID))
1738 		return wpas_dbus_error_invalid_args(message, NULL);
1739 
1740 	/* Extract the network ID and ensure the network */
1741 	/* is actually a child of this interface */
1742 	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
1743 	if (iface == NULL || net_id == NULL ||
1744 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1745 		reply = wpas_dbus_error_invalid_args(message, op);
1746 		goto out;
1747 	}
1748 
1749 	errno = 0;
1750 	id = strtoul(net_id, NULL, 10);
1751 	if (errno != 0) {
1752 		reply = wpas_dbus_error_invalid_args(message, net_id);
1753 		goto out;
1754 	}
1755 
1756 	ssid = wpa_config_get_network(wpa_s->conf, id);
1757 	if (ssid == NULL) {
1758 		reply = wpas_dbus_error_network_unknown(message);
1759 		goto out;
1760 	}
1761 
1762 	if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
1763 						      field, value) < 0)
1764 		reply = wpas_dbus_error_invalid_args(message, field);
1765 	else {
1766 		/* Tell EAP to retry immediately */
1767 		eapol_sm_notify_ctrl_response(wpa_s->eapol);
1768 	}
1769 
1770 out:
1771 	os_free(iface);
1772 	os_free(net_id);
1773 	return reply;
1774 #else /* IEEE8021X_EAPOL */
1775 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1776 	return wpas_dbus_error_unknown_error(message, "802.1X not included");
1777 #endif /* IEEE8021X_EAPOL */
1778 }
1779 
1780 
1781 #ifndef CONFIG_NO_CONFIG_BLOBS
1782 
1783 /**
1784  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
1785  * @message: Pointer to incoming dbus message
1786  * @wpa_s: %wpa_supplicant data structure
1787  * Returns: A dbus message containing an error on failure or NULL on success
1788  *
1789  * Asks wpa_supplicant to internally store a binary blobs.
1790  */
wpas_dbus_handler_add_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)1791 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
1792 					 struct wpa_supplicant *wpa_s)
1793 {
1794 	DBusMessage *reply = NULL;
1795 	DBusMessageIter	iter, array_iter;
1796 
1797 	char *blob_name;
1798 	u8 *blob_data;
1799 	int blob_len;
1800 	struct wpa_config_blob *blob = NULL;
1801 
1802 	dbus_message_iter_init(message, &iter);
1803 	dbus_message_iter_get_basic(&iter, &blob_name);
1804 
1805 	if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
1806 		return dbus_message_new_error(message,
1807 					      WPAS_DBUS_ERROR_BLOB_EXISTS,
1808 					      NULL);
1809 	}
1810 
1811 	dbus_message_iter_next(&iter);
1812 	dbus_message_iter_recurse(&iter, &array_iter);
1813 
1814 	dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
1815 
1816 	blob = os_zalloc(sizeof(*blob));
1817 	if (!blob) {
1818 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1819 					       NULL);
1820 		goto err;
1821 	}
1822 
1823 	blob->data = os_malloc(blob_len);
1824 	if (!blob->data) {
1825 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1826 					       NULL);
1827 		goto err;
1828 	}
1829 	os_memcpy(blob->data, blob_data, blob_len);
1830 
1831 	blob->len = blob_len;
1832 	blob->name = os_strdup(blob_name);
1833 	if (!blob->name) {
1834 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1835 					       NULL);
1836 		goto err;
1837 	}
1838 
1839 	wpa_config_set_blob(wpa_s->conf, blob);
1840 	wpas_notify_blob_added(wpa_s, blob->name);
1841 
1842 	return reply;
1843 
1844 err:
1845 	if (blob) {
1846 		os_free(blob->name);
1847 		os_free(blob->data);
1848 		os_free(blob);
1849 	}
1850 	return reply;
1851 }
1852 
1853 
1854 /**
1855  * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
1856  * @message: Pointer to incoming dbus message
1857  * @wpa_s: %wpa_supplicant data structure
1858  * Returns: A dbus message containing array of bytes (blob)
1859  *
1860  * Gets one wpa_supplicant's binary blobs.
1861  */
wpas_dbus_handler_get_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)1862 DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
1863 					 struct wpa_supplicant *wpa_s)
1864 {
1865 	DBusMessage *reply = NULL;
1866 	DBusMessageIter	iter, array_iter;
1867 
1868 	char *blob_name;
1869 	const struct wpa_config_blob *blob;
1870 
1871 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1872 			      DBUS_TYPE_INVALID);
1873 
1874 	blob = wpa_config_get_blob(wpa_s->conf, blob_name);
1875 	if (!blob) {
1876 		return dbus_message_new_error(message,
1877 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1878 					      "Blob id not set");
1879 	}
1880 
1881 	reply = dbus_message_new_method_return(message);
1882 	if (!reply) {
1883 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1884 					       NULL);
1885 		goto out;
1886 	}
1887 
1888 	dbus_message_iter_init_append(reply, &iter);
1889 
1890 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1891 					      DBUS_TYPE_BYTE_AS_STRING,
1892 					      &array_iter)) {
1893 		dbus_message_unref(reply);
1894 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1895 					       NULL);
1896 		goto out;
1897 	}
1898 
1899 	if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
1900 						  &(blob->data), blob->len)) {
1901 		dbus_message_unref(reply);
1902 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1903 					       NULL);
1904 		goto out;
1905 	}
1906 
1907 	if (!dbus_message_iter_close_container(&iter, &array_iter)) {
1908 		dbus_message_unref(reply);
1909 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1910 					       NULL);
1911 		goto out;
1912 	}
1913 
1914 out:
1915 	return reply;
1916 }
1917 
1918 
1919 /**
1920  * wpas_remove_handler_remove_blob - Remove named binary blob
1921  * @message: Pointer to incoming dbus message
1922  * @wpa_s: %wpa_supplicant data structure
1923  * Returns: NULL on success or dbus error
1924  *
1925  * Asks wpa_supplicant to internally remove a binary blobs.
1926  */
wpas_dbus_handler_remove_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)1927 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
1928 					    struct wpa_supplicant *wpa_s)
1929 {
1930 	DBusMessage *reply = NULL;
1931 	char *blob_name;
1932 
1933 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1934 			      DBUS_TYPE_INVALID);
1935 
1936 	if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
1937 		return dbus_message_new_error(message,
1938 					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1939 					      "Blob id not set");
1940 	}
1941 	wpas_notify_blob_removed(wpa_s, blob_name);
1942 
1943 	return reply;
1944 
1945 }
1946 
1947 #endif /* CONFIG_NO_CONFIG_BLOBS */
1948 
1949 
1950 /*
1951  * wpas_dbus_handler_flush_bss - Flush the BSS cache
1952  * @message: Pointer to incoming dbus message
1953  * @wpa_s: wpa_supplicant structure for a network interface
1954  * Returns: NULL
1955  *
1956  * Handler function for "FlushBSS" method call of network interface.
1957  */
wpas_dbus_handler_flush_bss(DBusMessage * message,struct wpa_supplicant * wpa_s)1958 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
1959 					  struct wpa_supplicant *wpa_s)
1960 {
1961 	dbus_uint32_t age;
1962 
1963 	dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
1964 			      DBUS_TYPE_INVALID);
1965 
1966 	if (age == 0)
1967 		wpa_bss_flush(wpa_s);
1968 	else
1969 		wpa_bss_flush_by_age(wpa_s, age);
1970 
1971 	return NULL;
1972 }
1973 
1974 
1975 #ifdef CONFIG_AUTOSCAN
1976 /**
1977  * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
1978  * @message: Pointer to incoming dbus message
1979  * @wpa_s: wpa_supplicant structure for a network interface
1980  * Returns: NULL
1981  *
1982  * Handler function for "AutoScan" method call of network interface.
1983  */
wpas_dbus_handler_autoscan(DBusMessage * message,struct wpa_supplicant * wpa_s)1984 DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
1985 					 struct wpa_supplicant *wpa_s)
1986 {
1987 	DBusMessage *reply = NULL;
1988 	enum wpa_states state = wpa_s->wpa_state;
1989 	char *arg;
1990 
1991 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
1992 			      DBUS_TYPE_INVALID);
1993 
1994 	if (arg != NULL && os_strlen(arg) > 0) {
1995 		char *tmp;
1996 		tmp = os_strdup(arg);
1997 		if (tmp == NULL) {
1998 			reply = dbus_message_new_error(message,
1999 						       DBUS_ERROR_NO_MEMORY,
2000 						       NULL);
2001 		} else {
2002 			os_free(wpa_s->conf->autoscan);
2003 			wpa_s->conf->autoscan = tmp;
2004 			if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
2005 				autoscan_init(wpa_s, 1);
2006 			else if (state == WPA_SCANNING)
2007 				wpa_supplicant_reinit_autoscan(wpa_s);
2008 		}
2009 	} else if (arg != NULL && os_strlen(arg) == 0) {
2010 		os_free(wpa_s->conf->autoscan);
2011 		wpa_s->conf->autoscan = NULL;
2012 		autoscan_deinit(wpa_s);
2013 	} else
2014 		reply = dbus_message_new_error(message,
2015 					       DBUS_ERROR_INVALID_ARGS,
2016 					       NULL);
2017 
2018 	return reply;
2019 }
2020 #endif /* CONFIG_AUTOSCAN */
2021 
2022 
2023 /*
2024  * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
2025  * @message: Pointer to incoming dbus message
2026  * @wpa_s: wpa_supplicant structure for a network interface
2027  * Returns: NULL
2028  *
2029  * Handler function for "EAPLogoff" method call of network interface.
2030  */
wpas_dbus_handler_eap_logoff(DBusMessage * message,struct wpa_supplicant * wpa_s)2031 DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
2032 					   struct wpa_supplicant *wpa_s)
2033 {
2034 	eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
2035 	return NULL;
2036 }
2037 
2038 
2039 /*
2040  * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
2041  * @message: Pointer to incoming dbus message
2042  * @wpa_s: wpa_supplicant structure for a network interface
2043  * Returns: NULL
2044  *
2045  * Handler function for "EAPLogin" method call of network interface.
2046  */
wpas_dbus_handler_eap_logon(DBusMessage * message,struct wpa_supplicant * wpa_s)2047 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
2048 					  struct wpa_supplicant *wpa_s)
2049 {
2050 	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
2051 	return NULL;
2052 }
2053 
2054 
2055 #ifdef CONFIG_TDLS
2056 
get_peer_hwaddr_helper(DBusMessage * message,const char * func_name,u8 * peer_address,DBusMessage ** error)2057 static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
2058 				  u8 *peer_address, DBusMessage **error)
2059 {
2060 	const char *peer_string;
2061 
2062 	*error = NULL;
2063 
2064 	if (!dbus_message_get_args(message, NULL,
2065 				   DBUS_TYPE_STRING, &peer_string,
2066 				   DBUS_TYPE_INVALID)) {
2067 		*error = wpas_dbus_error_invalid_args(message, NULL);
2068 		return -1;
2069 	}
2070 
2071 	if (hwaddr_aton(peer_string, peer_address)) {
2072 		wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
2073 			   func_name, peer_string);
2074 		*error = wpas_dbus_error_invalid_args(
2075 			message, "Invalid hardware address format");
2076 		return -1;
2077 	}
2078 
2079 	return 0;
2080 }
2081 
2082 
2083 /*
2084  * wpas_dbus_handler_tdls_discover - Discover TDLS peer
2085  * @message: Pointer to incoming dbus message
2086  * @wpa_s: wpa_supplicant structure for a network interface
2087  * Returns: NULL indicating success or DBus error message on failure
2088  *
2089  * Handler function for "TDLSDiscover" method call of network interface.
2090  */
wpas_dbus_handler_tdls_discover(DBusMessage * message,struct wpa_supplicant * wpa_s)2091 DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
2092 					      struct wpa_supplicant *wpa_s)
2093 {
2094 	u8 peer[ETH_ALEN];
2095 	DBusMessage *error_reply;
2096 	int ret;
2097 
2098 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2099 		return error_reply;
2100 
2101 	wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
2102 
2103 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2104 		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
2105 	else
2106 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
2107 
2108 	if (ret) {
2109 		return wpas_dbus_error_unknown_error(
2110 			message, "error performing TDLS discovery");
2111 	}
2112 
2113 	return NULL;
2114 }
2115 
2116 
2117 /*
2118  * wpas_dbus_handler_tdls_setup - Setup TDLS session
2119  * @message: Pointer to incoming dbus message
2120  * @wpa_s: wpa_supplicant structure for a network interface
2121  * Returns: NULL indicating success or DBus error message on failure
2122  *
2123  * Handler function for "TDLSSetup" method call of network interface.
2124  */
wpas_dbus_handler_tdls_setup(DBusMessage * message,struct wpa_supplicant * wpa_s)2125 DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
2126 					   struct wpa_supplicant *wpa_s)
2127 {
2128 	u8 peer[ETH_ALEN];
2129 	DBusMessage *error_reply;
2130 	int ret;
2131 
2132 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2133 		return error_reply;
2134 
2135 	wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
2136 
2137 	wpa_tdls_remove(wpa_s->wpa, peer);
2138 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2139 		ret = wpa_tdls_start(wpa_s->wpa, peer);
2140 	else
2141 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2142 
2143 	if (ret) {
2144 		return wpas_dbus_error_unknown_error(
2145 			message, "error performing TDLS setup");
2146 	}
2147 
2148 	return NULL;
2149 }
2150 
2151 
2152 /*
2153  * wpas_dbus_handler_tdls_status - Return TDLS session status
2154  * @message: Pointer to incoming dbus message
2155  * @wpa_s: wpa_supplicant structure for a network interface
2156  * Returns: A string representing the state of the link to this TDLS peer
2157  *
2158  * Handler function for "TDLSStatus" method call of network interface.
2159  */
wpas_dbus_handler_tdls_status(DBusMessage * message,struct wpa_supplicant * wpa_s)2160 DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
2161 					    struct wpa_supplicant *wpa_s)
2162 {
2163 	u8 peer[ETH_ALEN];
2164 	DBusMessage *reply;
2165 	const char *tdls_status;
2166 
2167 	if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
2168 		return reply;
2169 
2170 	wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
2171 
2172 	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
2173 
2174 	reply = dbus_message_new_method_return(message);
2175 	dbus_message_append_args(reply, DBUS_TYPE_STRING,
2176 				 &tdls_status, DBUS_TYPE_INVALID);
2177 	return reply;
2178 }
2179 
2180 
2181 /*
2182  * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
2183  * @message: Pointer to incoming dbus message
2184  * @wpa_s: wpa_supplicant structure for a network interface
2185  * Returns: NULL indicating success or DBus error message on failure
2186  *
2187  * Handler function for "TDLSTeardown" method call of network interface.
2188  */
wpas_dbus_handler_tdls_teardown(DBusMessage * message,struct wpa_supplicant * wpa_s)2189 DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
2190 					      struct wpa_supplicant *wpa_s)
2191 {
2192 	u8 peer[ETH_ALEN];
2193 	DBusMessage *error_reply;
2194 	int ret;
2195 
2196 	if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2197 		return error_reply;
2198 
2199 	wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
2200 
2201 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
2202 		ret = wpa_tdls_teardown_link(
2203 			wpa_s->wpa, peer,
2204 			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
2205 	else
2206 		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
2207 
2208 	if (ret) {
2209 		return wpas_dbus_error_unknown_error(
2210 			message, "error performing TDLS teardown");
2211 	}
2212 
2213 	return NULL;
2214 }
2215 
2216 #endif /* CONFIG_TDLS */
2217 
2218 
2219 /**
2220  * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
2221  * @message: Pointer to incoming dbus message
2222  * @wpa_s: %wpa_supplicant data structure
2223  * Returns: A dbus message containing an error on failure or NULL on success
2224  *
2225  * Sets the PKCS #11 engine and module path.
2226  */
wpas_dbus_handler_set_pkcs11_engine_and_module_path(DBusMessage * message,struct wpa_supplicant * wpa_s)2227 DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
2228 	DBusMessage *message, struct wpa_supplicant *wpa_s)
2229 {
2230 	DBusMessageIter iter;
2231 	char *value = NULL;
2232 	char *pkcs11_engine_path = NULL;
2233 	char *pkcs11_module_path = NULL;
2234 
2235 	dbus_message_iter_init(message, &iter);
2236 	dbus_message_iter_get_basic(&iter, &value);
2237 	if (value == NULL) {
2238 		return dbus_message_new_error(
2239 			message, DBUS_ERROR_INVALID_ARGS,
2240 			"Invalid pkcs11_engine_path argument");
2241 	}
2242 	/* Empty path defaults to NULL */
2243 	if (os_strlen(value))
2244 		pkcs11_engine_path = value;
2245 
2246 	dbus_message_iter_next(&iter);
2247 	dbus_message_iter_get_basic(&iter, &value);
2248 	if (value == NULL) {
2249 		os_free(pkcs11_engine_path);
2250 		return dbus_message_new_error(
2251 			message, DBUS_ERROR_INVALID_ARGS,
2252 			"Invalid pkcs11_module_path argument");
2253 	}
2254 	/* Empty path defaults to NULL */
2255 	if (os_strlen(value))
2256 		pkcs11_module_path = value;
2257 
2258 	if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
2259 						   pkcs11_module_path))
2260 		return dbus_message_new_error(
2261 			message, DBUS_ERROR_FAILED,
2262 			"Reinit of the EAPOL state machine with the new PKCS "
2263 			"#11 engine and module path failed.");
2264 
2265 	wpa_dbus_mark_property_changed(
2266 		wpa_s->global->dbus, wpa_s->dbus_new_path,
2267 		WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
2268 	wpa_dbus_mark_property_changed(
2269 		wpa_s->global->dbus, wpa_s->dbus_new_path,
2270 		WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
2271 
2272 	return NULL;
2273 }
2274 
2275 
2276 /**
2277  * wpas_dbus_getter_capabilities - Return interface capabilities
2278  * @iter: Pointer to incoming dbus message iter
2279  * @error: Location to store error on failure
2280  * @user_data: Function specific data
2281  * Returns: TRUE on success, FALSE on failure
2282  *
2283  * Getter for "Capabilities" property of an interface.
2284  */
wpas_dbus_getter_capabilities(DBusMessageIter * iter,DBusError * error,void * user_data)2285 dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
2286 					  DBusError *error, void *user_data)
2287 {
2288 	struct wpa_supplicant *wpa_s = user_data;
2289 	struct wpa_driver_capa capa;
2290 	int res;
2291 	DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
2292 		variant_iter;
2293 	const char *scans[] = { "active", "passive", "ssid" };
2294 
2295 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
2296 					      "a{sv}", &variant_iter))
2297 		goto nomem;
2298 
2299 	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
2300 		goto nomem;
2301 
2302 	res = wpa_drv_get_capa(wpa_s, &capa);
2303 
2304 	/***** pairwise cipher */
2305 	if (res < 0) {
2306 		const char *args[] = {"ccmp", "tkip", "none"};
2307 		if (!wpa_dbus_dict_append_string_array(
2308 			    &iter_dict, "Pairwise", args,
2309 			    ARRAY_SIZE(args)))
2310 			goto nomem;
2311 	} else {
2312 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
2313 						      &iter_dict_entry,
2314 						      &iter_dict_val,
2315 						      &iter_array))
2316 			goto nomem;
2317 
2318 		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
2319 			if (!wpa_dbus_dict_string_array_add_element(
2320 				    &iter_array, "ccmp-256"))
2321 				goto nomem;
2322 		}
2323 
2324 		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
2325 			if (!wpa_dbus_dict_string_array_add_element(
2326 				    &iter_array, "gcmp-256"))
2327 				goto nomem;
2328 		}
2329 
2330 		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2331 			if (!wpa_dbus_dict_string_array_add_element(
2332 				    &iter_array, "ccmp"))
2333 				goto nomem;
2334 		}
2335 
2336 		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2337 			if (!wpa_dbus_dict_string_array_add_element(
2338 				    &iter_array, "gcmp"))
2339 				goto nomem;
2340 		}
2341 
2342 		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2343 			if (!wpa_dbus_dict_string_array_add_element(
2344 				    &iter_array, "tkip"))
2345 				goto nomem;
2346 		}
2347 
2348 		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2349 			if (!wpa_dbus_dict_string_array_add_element(
2350 				    &iter_array, "none"))
2351 				goto nomem;
2352 		}
2353 
2354 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2355 						    &iter_dict_entry,
2356 						    &iter_dict_val,
2357 						    &iter_array))
2358 			goto nomem;
2359 	}
2360 
2361 	/***** group cipher */
2362 	if (res < 0) {
2363 		const char *args[] = {
2364 			"ccmp", "tkip", "wep104", "wep40"
2365 		};
2366 		if (!wpa_dbus_dict_append_string_array(
2367 			    &iter_dict, "Group", args,
2368 			    ARRAY_SIZE(args)))
2369 			goto nomem;
2370 	} else {
2371 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
2372 						      &iter_dict_entry,
2373 						      &iter_dict_val,
2374 						      &iter_array))
2375 			goto nomem;
2376 
2377 		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
2378 			if (!wpa_dbus_dict_string_array_add_element(
2379 				    &iter_array, "ccmp-256"))
2380 				goto nomem;
2381 		}
2382 
2383 		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
2384 			if (!wpa_dbus_dict_string_array_add_element(
2385 				    &iter_array, "gcmp-256"))
2386 				goto nomem;
2387 		}
2388 
2389 		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2390 			if (!wpa_dbus_dict_string_array_add_element(
2391 				    &iter_array, "ccmp"))
2392 				goto nomem;
2393 		}
2394 
2395 		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2396 			if (!wpa_dbus_dict_string_array_add_element(
2397 				    &iter_array, "gcmp"))
2398 				goto nomem;
2399 		}
2400 
2401 		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2402 			if (!wpa_dbus_dict_string_array_add_element(
2403 				    &iter_array, "tkip"))
2404 				goto nomem;
2405 		}
2406 
2407 		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
2408 			if (!wpa_dbus_dict_string_array_add_element(
2409 				    &iter_array, "wep104"))
2410 				goto nomem;
2411 		}
2412 
2413 		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
2414 			if (!wpa_dbus_dict_string_array_add_element(
2415 				    &iter_array, "wep40"))
2416 				goto nomem;
2417 		}
2418 
2419 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2420 						    &iter_dict_entry,
2421 						    &iter_dict_val,
2422 						    &iter_array))
2423 			goto nomem;
2424 	}
2425 
2426 	/***** key management */
2427 	if (res < 0) {
2428 		const char *args[] = {
2429 			"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
2430 #ifdef CONFIG_WPS
2431 			"wps",
2432 #endif /* CONFIG_WPS */
2433 			"none"
2434 		};
2435 		if (!wpa_dbus_dict_append_string_array(
2436 			    &iter_dict, "KeyMgmt", args,
2437 			    ARRAY_SIZE(args)))
2438 			goto nomem;
2439 	} else {
2440 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
2441 						      &iter_dict_entry,
2442 						      &iter_dict_val,
2443 						      &iter_array))
2444 			goto nomem;
2445 
2446 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2447 							    "none"))
2448 			goto nomem;
2449 
2450 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2451 							    "ieee8021x"))
2452 			goto nomem;
2453 
2454 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2455 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2456 			if (!wpa_dbus_dict_string_array_add_element(
2457 				    &iter_array, "wpa-eap"))
2458 				goto nomem;
2459 
2460 			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
2461 				if (!wpa_dbus_dict_string_array_add_element(
2462 					    &iter_array, "wpa-ft-eap"))
2463 					goto nomem;
2464 
2465 /* TODO: Ensure that driver actually supports sha256 encryption. */
2466 #ifdef CONFIG_IEEE80211W
2467 			if (!wpa_dbus_dict_string_array_add_element(
2468 				    &iter_array, "wpa-eap-sha256"))
2469 				goto nomem;
2470 #endif /* CONFIG_IEEE80211W */
2471 		}
2472 
2473 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2474 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2475 			if (!wpa_dbus_dict_string_array_add_element(
2476 				    &iter_array, "wpa-psk"))
2477 				goto nomem;
2478 
2479 			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
2480 				if (!wpa_dbus_dict_string_array_add_element(
2481 					    &iter_array, "wpa-ft-psk"))
2482 					goto nomem;
2483 
2484 /* TODO: Ensure that driver actually supports sha256 encryption. */
2485 #ifdef CONFIG_IEEE80211W
2486 			if (!wpa_dbus_dict_string_array_add_element(
2487 				    &iter_array, "wpa-psk-sha256"))
2488 				goto nomem;
2489 #endif /* CONFIG_IEEE80211W */
2490 		}
2491 
2492 		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2493 			if (!wpa_dbus_dict_string_array_add_element(
2494 				    &iter_array, "wpa-none"))
2495 				goto nomem;
2496 		}
2497 
2498 
2499 #ifdef CONFIG_WPS
2500 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2501 							    "wps"))
2502 			goto nomem;
2503 #endif /* CONFIG_WPS */
2504 
2505 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2506 						    &iter_dict_entry,
2507 						    &iter_dict_val,
2508 						    &iter_array))
2509 			goto nomem;
2510 	}
2511 
2512 	/***** WPA protocol */
2513 	if (res < 0) {
2514 		const char *args[] = { "rsn", "wpa" };
2515 		if (!wpa_dbus_dict_append_string_array(
2516 			    &iter_dict, "Protocol", args,
2517 			    ARRAY_SIZE(args)))
2518 			goto nomem;
2519 	} else {
2520 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
2521 						      &iter_dict_entry,
2522 						      &iter_dict_val,
2523 						      &iter_array))
2524 			goto nomem;
2525 
2526 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2527 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2528 			if (!wpa_dbus_dict_string_array_add_element(
2529 				    &iter_array, "rsn"))
2530 				goto nomem;
2531 		}
2532 
2533 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2534 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
2535 			if (!wpa_dbus_dict_string_array_add_element(
2536 				    &iter_array, "wpa"))
2537 				goto nomem;
2538 		}
2539 
2540 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2541 						    &iter_dict_entry,
2542 						    &iter_dict_val,
2543 						    &iter_array))
2544 			goto nomem;
2545 	}
2546 
2547 	/***** auth alg */
2548 	if (res < 0) {
2549 		const char *args[] = { "open", "shared", "leap" };
2550 		if (!wpa_dbus_dict_append_string_array(
2551 			    &iter_dict, "AuthAlg", args,
2552 			    ARRAY_SIZE(args)))
2553 			goto nomem;
2554 	} else {
2555 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
2556 						      &iter_dict_entry,
2557 						      &iter_dict_val,
2558 						      &iter_array))
2559 			goto nomem;
2560 
2561 		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
2562 			if (!wpa_dbus_dict_string_array_add_element(
2563 				    &iter_array, "open"))
2564 				goto nomem;
2565 		}
2566 
2567 		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
2568 			if (!wpa_dbus_dict_string_array_add_element(
2569 				    &iter_array, "shared"))
2570 				goto nomem;
2571 		}
2572 
2573 		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
2574 			if (!wpa_dbus_dict_string_array_add_element(
2575 				    &iter_array, "leap"))
2576 				goto nomem;
2577 		}
2578 
2579 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
2580 						    &iter_dict_entry,
2581 						    &iter_dict_val,
2582 						    &iter_array))
2583 			goto nomem;
2584 	}
2585 
2586 	/***** Scan */
2587 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
2588 					       ARRAY_SIZE(scans)))
2589 		goto nomem;
2590 
2591 	/***** Modes */
2592 	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
2593 					      &iter_dict_entry,
2594 					      &iter_dict_val,
2595 					      &iter_array))
2596 		goto nomem;
2597 
2598 	if (!wpa_dbus_dict_string_array_add_element(
2599 			    &iter_array, "infrastructure"))
2600 		goto nomem;
2601 
2602 	if (!wpa_dbus_dict_string_array_add_element(
2603 			    &iter_array, "ad-hoc"))
2604 		goto nomem;
2605 
2606 	if (res >= 0) {
2607 		if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
2608 			if (!wpa_dbus_dict_string_array_add_element(
2609 				    &iter_array, "ap"))
2610 				goto nomem;
2611 		}
2612 
2613 		if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
2614 			if (!wpa_dbus_dict_string_array_add_element(
2615 				    &iter_array, "p2p"))
2616 				goto nomem;
2617 		}
2618 	}
2619 
2620 	if (!wpa_dbus_dict_end_string_array(&iter_dict,
2621 					    &iter_dict_entry,
2622 					    &iter_dict_val,
2623 					    &iter_array))
2624 		goto nomem;
2625 	/***** Modes end */
2626 
2627 	if (res >= 0) {
2628 		dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
2629 
2630 		if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
2631 						max_scan_ssid))
2632 			goto nomem;
2633 	}
2634 
2635 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
2636 		goto nomem;
2637 	if (!dbus_message_iter_close_container(iter, &variant_iter))
2638 		goto nomem;
2639 
2640 	return TRUE;
2641 
2642 nomem:
2643 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2644 	return FALSE;
2645 }
2646 
2647 
2648 /**
2649  * wpas_dbus_getter_state - Get interface state
2650  * @iter: Pointer to incoming dbus message iter
2651  * @error: Location to store error on failure
2652  * @user_data: Function specific data
2653  * Returns: TRUE on success, FALSE on failure
2654  *
2655  * Getter for "State" property.
2656  */
wpas_dbus_getter_state(DBusMessageIter * iter,DBusError * error,void * user_data)2657 dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
2658 				   void *user_data)
2659 {
2660 	struct wpa_supplicant *wpa_s = user_data;
2661 	const char *str_state;
2662 	char *state_ls, *tmp;
2663 	dbus_bool_t success = FALSE;
2664 
2665 	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
2666 
2667 	/* make state string lowercase to fit new DBus API convention
2668 	 */
2669 	state_ls = tmp = os_strdup(str_state);
2670 	if (!tmp) {
2671 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2672 		return FALSE;
2673 	}
2674 	while (*tmp) {
2675 		*tmp = tolower(*tmp);
2676 		tmp++;
2677 	}
2678 
2679 	success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2680 						   &state_ls, error);
2681 
2682 	os_free(state_ls);
2683 
2684 	return success;
2685 }
2686 
2687 
2688 /**
2689  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
2690  * @iter: Pointer to incoming dbus message iter
2691  * @error: Location to store error on failure
2692  * @user_data: Function specific data
2693  * Returns: TRUE on success, FALSE on failure
2694  *
2695  * Getter for "scanning" property.
2696  */
wpas_dbus_getter_scanning(DBusMessageIter * iter,DBusError * error,void * user_data)2697 dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
2698                                       void *user_data)
2699 {
2700 	struct wpa_supplicant *wpa_s = user_data;
2701 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
2702 
2703 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2704 						&scanning, error);
2705 }
2706 
2707 
2708 /**
2709  * wpas_dbus_getter_ap_scan - Control roaming mode
2710  * @iter: Pointer to incoming dbus message iter
2711  * @error: Location to store error on failure
2712  * @user_data: Function specific data
2713  * Returns: TRUE on success, FALSE on failure
2714  *
2715  * Getter function for "ApScan" property.
2716  */
wpas_dbus_getter_ap_scan(DBusMessageIter * iter,DBusError * error,void * user_data)2717 dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
2718 				     void *user_data)
2719 {
2720 	struct wpa_supplicant *wpa_s = user_data;
2721 	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
2722 
2723 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2724 						&ap_scan, error);
2725 }
2726 
2727 
2728 /**
2729  * wpas_dbus_setter_ap_scan - Control roaming mode
2730  * @iter: Pointer to incoming dbus message iter
2731  * @error: Location to store error on failure
2732  * @user_data: Function specific data
2733  * Returns: TRUE on success, FALSE on failure
2734  *
2735  * Setter function for "ApScan" property.
2736  */
wpas_dbus_setter_ap_scan(DBusMessageIter * iter,DBusError * error,void * user_data)2737 dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
2738 				     void *user_data)
2739 {
2740 	struct wpa_supplicant *wpa_s = user_data;
2741 	dbus_uint32_t ap_scan;
2742 
2743 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2744 					      &ap_scan))
2745 		return FALSE;
2746 
2747 	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
2748 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2749 				     "ap_scan must be 0, 1, or 2");
2750 		return FALSE;
2751 	}
2752 	return TRUE;
2753 }
2754 
2755 
2756 /**
2757  * wpas_dbus_getter_fast_reauth - Control fast
2758  * reauthentication (TLS session resumption)
2759  * @iter: Pointer to incoming dbus message iter
2760  * @error: Location to store error on failure
2761  * @user_data: Function specific data
2762  * Returns: TRUE on success, FALSE on failure
2763  *
2764  * Getter function for "FastReauth" property.
2765  */
wpas_dbus_getter_fast_reauth(DBusMessageIter * iter,DBusError * error,void * user_data)2766 dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
2767 					 DBusError *error,
2768 					 void *user_data)
2769 {
2770 	struct wpa_supplicant *wpa_s = user_data;
2771 	dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
2772 
2773 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2774 						&fast_reauth, error);
2775 }
2776 
2777 
2778 /**
2779  * wpas_dbus_setter_fast_reauth - Control fast
2780  * reauthentication (TLS session resumption)
2781  * @iter: Pointer to incoming dbus message iter
2782  * @error: Location to store error on failure
2783  * @user_data: Function specific data
2784  * Returns: TRUE on success, FALSE on failure
2785  *
2786  * Setter function for "FastReauth" property.
2787  */
wpas_dbus_setter_fast_reauth(DBusMessageIter * iter,DBusError * error,void * user_data)2788 dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
2789 				     DBusError *error,
2790 				     void *user_data)
2791 {
2792 	struct wpa_supplicant *wpa_s = user_data;
2793 	dbus_bool_t fast_reauth;
2794 
2795 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
2796 					      &fast_reauth))
2797 		return FALSE;
2798 
2799 	wpa_s->conf->fast_reauth = fast_reauth;
2800 	return TRUE;
2801 }
2802 
2803 
2804 /**
2805  * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
2806  * @iter: Pointer to incoming dbus message iter
2807  * @error: Location to store error on failure
2808  * @user_data: Function specific data
2809  * Returns: TRUE on success, FALSE on failure
2810  *
2811  * Getter for "DisconnectReason" property.  The reason is negative if it is
2812  * locally generated.
2813  */
wpas_dbus_getter_disconnect_reason(DBusMessageIter * iter,DBusError * error,void * user_data)2814 dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
2815 					       DBusError *error,
2816 					       void *user_data)
2817 {
2818 	struct wpa_supplicant *wpa_s = user_data;
2819 	dbus_int32_t reason = wpa_s->disconnect_reason;
2820 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
2821 						&reason, error);
2822 }
2823 
2824 
2825 /**
2826  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
2827  * @iter: Pointer to incoming dbus message iter
2828  * @error: Location to store error on failure
2829  * @user_data: Function specific data
2830  * Returns: TRUE on success, FALSE on failure
2831  *
2832  * Getter function for "BSSExpireAge" property.
2833  */
wpas_dbus_getter_bss_expire_age(DBusMessageIter * iter,DBusError * error,void * user_data)2834 dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
2835 					    DBusError *error,
2836 					    void *user_data)
2837 {
2838 	struct wpa_supplicant *wpa_s = user_data;
2839 	dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
2840 
2841 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2842 						&expire_age, error);
2843 }
2844 
2845 
2846 /**
2847  * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
2848  * @iter: Pointer to incoming dbus message iter
2849  * @error: Location to store error on failure
2850  * @user_data: Function specific data
2851  * Returns: TRUE on success, FALSE on failure
2852  *
2853  * Setter function for "BSSExpireAge" property.
2854  */
wpas_dbus_setter_bss_expire_age(DBusMessageIter * iter,DBusError * error,void * user_data)2855 dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
2856 					    DBusError *error,
2857 					    void *user_data)
2858 {
2859 	struct wpa_supplicant *wpa_s = user_data;
2860 	dbus_uint32_t expire_age;
2861 
2862 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2863 					      &expire_age))
2864 		return FALSE;
2865 
2866 	if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
2867 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2868 				     "BSSExpireAge must be >= 10");
2869 		return FALSE;
2870 	}
2871 	return TRUE;
2872 }
2873 
2874 
2875 /**
2876  * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
2877  * @iter: Pointer to incoming dbus message iter
2878  * @error: Location to store error on failure
2879  * @user_data: Function specific data
2880  * Returns: TRUE on success, FALSE on failure
2881  *
2882  * Getter function for "BSSExpireCount" property.
2883  */
wpas_dbus_getter_bss_expire_count(DBusMessageIter * iter,DBusError * error,void * user_data)2884 dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
2885 					      DBusError *error,
2886 					      void *user_data)
2887 {
2888 	struct wpa_supplicant *wpa_s = user_data;
2889 	dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
2890 
2891 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2892 						&expire_count, error);
2893 }
2894 
2895 
2896 /**
2897  * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
2898  * @iter: Pointer to incoming dbus message iter
2899  * @error: Location to store error on failure
2900  * @user_data: Function specific data
2901  * Returns: TRUE on success, FALSE on failure
2902  *
2903  * Setter function for "BSSExpireCount" property.
2904  */
wpas_dbus_setter_bss_expire_count(DBusMessageIter * iter,DBusError * error,void * user_data)2905 dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
2906 					      DBusError *error,
2907 					      void *user_data)
2908 {
2909 	struct wpa_supplicant *wpa_s = user_data;
2910 	dbus_uint32_t expire_count;
2911 
2912 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
2913 					      &expire_count))
2914 		return FALSE;
2915 
2916 	if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
2917 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2918 				     "BSSExpireCount must be > 0");
2919 		return FALSE;
2920 	}
2921 	return TRUE;
2922 }
2923 
2924 
2925 /**
2926  * wpas_dbus_getter_country - Control country code
2927  * @iter: Pointer to incoming dbus message iter
2928  * @error: Location to store error on failure
2929  * @user_data: Function specific data
2930  * Returns: TRUE on success, FALSE on failure
2931  *
2932  * Getter function for "Country" property.
2933  */
wpas_dbus_getter_country(DBusMessageIter * iter,DBusError * error,void * user_data)2934 dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
2935 				     void *user_data)
2936 {
2937 	struct wpa_supplicant *wpa_s = user_data;
2938 	char country[3];
2939 	char *str = country;
2940 
2941 	country[0] = wpa_s->conf->country[0];
2942 	country[1] = wpa_s->conf->country[1];
2943 	country[2] = '\0';
2944 
2945 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2946 						&str, error);
2947 }
2948 
2949 
2950 /**
2951  * wpas_dbus_setter_country - Control country code
2952  * @iter: Pointer to incoming dbus message iter
2953  * @error: Location to store error on failure
2954  * @user_data: Function specific data
2955  * Returns: TRUE on success, FALSE on failure
2956  *
2957  * Setter function for "Country" property.
2958  */
wpas_dbus_setter_country(DBusMessageIter * iter,DBusError * error,void * user_data)2959 dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
2960 				     void *user_data)
2961 {
2962 	struct wpa_supplicant *wpa_s = user_data;
2963 	const char *country;
2964 
2965 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
2966 					      &country))
2967 		return FALSE;
2968 
2969 	if (!country[0] || !country[1]) {
2970 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2971 				     "invalid country code");
2972 		return FALSE;
2973 	}
2974 
2975 	if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
2976 		wpa_printf(MSG_DEBUG, "Failed to set country");
2977 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
2978 				     "failed to set country code");
2979 		return FALSE;
2980 	}
2981 
2982 	wpa_s->conf->country[0] = country[0];
2983 	wpa_s->conf->country[1] = country[1];
2984 	return TRUE;
2985 }
2986 
2987 
2988 /**
2989  * wpas_dbus_getter_scan_interval - Get scan interval
2990  * @iter: Pointer to incoming dbus message iter
2991  * @error: Location to store error on failure
2992  * @user_data: Function specific data
2993  * Returns: TRUE on success, FALSE on failure
2994  *
2995  * Getter function for "ScanInterval" property.
2996  */
wpas_dbus_getter_scan_interval(DBusMessageIter * iter,DBusError * error,void * user_data)2997 dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
2998 					   DBusError *error,
2999 					   void *user_data)
3000 {
3001 	struct wpa_supplicant *wpa_s = user_data;
3002 	dbus_int32_t scan_interval = wpa_s->scan_interval;
3003 
3004 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3005 						&scan_interval, error);
3006 }
3007 
3008 
3009 /**
3010  * wpas_dbus_setter_scan_interval - Control scan interval
3011  * @iter: Pointer to incoming dbus message iter
3012  * @error: Location to store error on failure
3013  * @user_data: Function specific data
3014  * Returns: TRUE on success, FALSE on failure
3015  *
3016  * Setter function for "ScanInterval" property.
3017  */
wpas_dbus_setter_scan_interval(DBusMessageIter * iter,DBusError * error,void * user_data)3018 dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
3019 					   DBusError *error,
3020 					   void *user_data)
3021 {
3022 	struct wpa_supplicant *wpa_s = user_data;
3023 	dbus_int32_t scan_interval;
3024 
3025 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
3026 					      &scan_interval))
3027 		return FALSE;
3028 
3029 	if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
3030 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
3031 				     "scan_interval must be >= 0");
3032 		return FALSE;
3033 	}
3034 	return TRUE;
3035 }
3036 
3037 
3038 /**
3039  * wpas_dbus_getter_ifname - Get interface name
3040  * @iter: Pointer to incoming dbus message iter
3041  * @error: Location to store error on failure
3042  * @user_data: Function specific data
3043  * Returns: TRUE on success, FALSE on failure
3044  *
3045  * Getter for "Ifname" property.
3046  */
wpas_dbus_getter_ifname(DBusMessageIter * iter,DBusError * error,void * user_data)3047 dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
3048 				    void *user_data)
3049 {
3050 	struct wpa_supplicant *wpa_s = user_data;
3051 	const char *ifname = wpa_s->ifname;
3052 
3053 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3054 						&ifname, error);
3055 }
3056 
3057 
3058 /**
3059  * wpas_dbus_getter_driver - Get interface name
3060  * @iter: Pointer to incoming dbus message iter
3061  * @error: Location to store error on failure
3062  * @user_data: Function specific data
3063  * Returns: TRUE on success, FALSE on failure
3064  *
3065  * Getter for "Driver" property.
3066  */
wpas_dbus_getter_driver(DBusMessageIter * iter,DBusError * error,void * user_data)3067 dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
3068 				    void *user_data)
3069 {
3070 	struct wpa_supplicant *wpa_s = user_data;
3071 	const char *driver;
3072 
3073 	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
3074 		wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
3075 			   "wpa_s has no driver set");
3076 		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
3077 			       __func__);
3078 		return FALSE;
3079 	}
3080 
3081 	driver = wpa_s->driver->name;
3082 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3083 						&driver, error);
3084 }
3085 
3086 
3087 /**
3088  * wpas_dbus_getter_current_bss - Get current bss object path
3089  * @iter: Pointer to incoming dbus message iter
3090  * @error: Location to store error on failure
3091  * @user_data: Function specific data
3092  * Returns: TRUE on success, FALSE on failure
3093  *
3094  * Getter for "CurrentBSS" property.
3095  */
wpas_dbus_getter_current_bss(DBusMessageIter * iter,DBusError * error,void * user_data)3096 dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
3097 					 DBusError *error,
3098 					 void *user_data)
3099 {
3100 	struct wpa_supplicant *wpa_s = user_data;
3101 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
3102 
3103 	if (wpa_s->current_bss)
3104 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3105 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3106 			    wpa_s->dbus_new_path, wpa_s->current_bss->id);
3107 	else
3108 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3109 
3110 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3111 						&bss_obj_path, error);
3112 }
3113 
3114 
3115 /**
3116  * wpas_dbus_getter_current_network - Get current network object path
3117  * @iter: Pointer to incoming dbus message iter
3118  * @error: Location to store error on failure
3119  * @user_data: Function specific data
3120  * Returns: TRUE on success, FALSE on failure
3121  *
3122  * Getter for "CurrentNetwork" property.
3123  */
wpas_dbus_getter_current_network(DBusMessageIter * iter,DBusError * error,void * user_data)3124 dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
3125 					     DBusError *error,
3126 					     void *user_data)
3127 {
3128 	struct wpa_supplicant *wpa_s = user_data;
3129 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
3130 
3131 	if (wpa_s->current_ssid)
3132 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3133 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
3134 			    wpa_s->dbus_new_path, wpa_s->current_ssid->id);
3135 	else
3136 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3137 
3138 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3139 						&net_obj_path, error);
3140 }
3141 
3142 
3143 /**
3144  * wpas_dbus_getter_current_auth_mode - Get current authentication type
3145  * @iter: Pointer to incoming dbus message iter
3146  * @error: Location to store error on failure
3147  * @user_data: Function specific data
3148  * Returns: TRUE on success, FALSE on failure
3149  *
3150  * Getter for "CurrentAuthMode" property.
3151  */
wpas_dbus_getter_current_auth_mode(DBusMessageIter * iter,DBusError * error,void * user_data)3152 dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
3153 					       DBusError *error,
3154 					       void *user_data)
3155 {
3156 	struct wpa_supplicant *wpa_s = user_data;
3157 	const char *eap_mode;
3158 	const char *auth_mode;
3159 	char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
3160 
3161 	if (wpa_s->wpa_state != WPA_COMPLETED) {
3162 		auth_mode = "INACTIVE";
3163 	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
3164 	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3165 		eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
3166 		os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
3167 			    "EAP-%s", eap_mode);
3168 		auth_mode = eap_mode_buf;
3169 
3170 	} else {
3171 		auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
3172 					     wpa_s->current_ssid->proto);
3173 	}
3174 
3175 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3176 						&auth_mode, error);
3177 }
3178 
3179 
3180 /**
3181  * wpas_dbus_getter_bridge_ifname - Get interface name
3182  * @iter: Pointer to incoming dbus message iter
3183  * @error: Location to store error on failure
3184  * @user_data: Function specific data
3185  * Returns: TRUE on success, FALSE on failure
3186  *
3187  * Getter for "BridgeIfname" property.
3188  */
wpas_dbus_getter_bridge_ifname(DBusMessageIter * iter,DBusError * error,void * user_data)3189 dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
3190 					   DBusError *error,
3191 					   void *user_data)
3192 {
3193 	struct wpa_supplicant *wpa_s = user_data;
3194 	const char *bridge_ifname = wpa_s->bridge_ifname;
3195 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3196 						&bridge_ifname, error);
3197 }
3198 
3199 
3200 /**
3201  * wpas_dbus_getter_bsss - Get array of BSSs objects
3202  * @iter: Pointer to incoming dbus message iter
3203  * @error: Location to store error on failure
3204  * @user_data: Function specific data
3205  * Returns: TRUE on success, FALSE on failure
3206  *
3207  * Getter for "BSSs" property.
3208  */
wpas_dbus_getter_bsss(DBusMessageIter * iter,DBusError * error,void * user_data)3209 dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
3210 				  void *user_data)
3211 {
3212 	struct wpa_supplicant *wpa_s = user_data;
3213 	struct wpa_bss *bss;
3214 	char **paths;
3215 	unsigned int i = 0;
3216 	dbus_bool_t success = FALSE;
3217 
3218 	paths = os_calloc(wpa_s->num_bss, sizeof(char *));
3219 	if (!paths) {
3220 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3221 		return FALSE;
3222 	}
3223 
3224 	/* Loop through scan results and append each result's object path */
3225 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
3226 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3227 		if (paths[i] == NULL) {
3228 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3229 					     "no memory");
3230 			goto out;
3231 		}
3232 		/* Construct the object path for this BSS. */
3233 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3234 			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3235 			    wpa_s->dbus_new_path, bss->id);
3236 	}
3237 
3238 	success = wpas_dbus_simple_array_property_getter(iter,
3239 							 DBUS_TYPE_OBJECT_PATH,
3240 							 paths, wpa_s->num_bss,
3241 							 error);
3242 
3243 out:
3244 	while (i)
3245 		os_free(paths[--i]);
3246 	os_free(paths);
3247 	return success;
3248 }
3249 
3250 
3251 /**
3252  * wpas_dbus_getter_networks - Get array of networks objects
3253  * @iter: Pointer to incoming dbus message iter
3254  * @error: Location to store error on failure
3255  * @user_data: Function specific data
3256  * Returns: TRUE on success, FALSE on failure
3257  *
3258  * Getter for "Networks" property.
3259  */
wpas_dbus_getter_networks(DBusMessageIter * iter,DBusError * error,void * user_data)3260 dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
3261 				      void *user_data)
3262 {
3263 	struct wpa_supplicant *wpa_s = user_data;
3264 	struct wpa_ssid *ssid;
3265 	char **paths;
3266 	unsigned int i = 0, num = 0;
3267 	dbus_bool_t success = FALSE;
3268 
3269 	if (wpa_s->conf == NULL) {
3270 		wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
3271 			   "networks list.", __func__);
3272 		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
3273 			       "occurred getting the networks list", __func__);
3274 		return FALSE;
3275 	}
3276 
3277 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
3278 		if (!network_is_persistent_group(ssid))
3279 			num++;
3280 
3281 	paths = os_calloc(num, sizeof(char *));
3282 	if (!paths) {
3283 		dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3284 		return FALSE;
3285 	}
3286 
3287 	/* Loop through configured networks and append object path of each */
3288 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
3289 		if (network_is_persistent_group(ssid))
3290 			continue;
3291 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3292 		if (paths[i] == NULL) {
3293 			dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3294 			goto out;
3295 		}
3296 
3297 		/* Construct the object path for this network. */
3298 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3299 			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
3300 			    wpa_s->dbus_new_path, ssid->id);
3301 	}
3302 
3303 	success = wpas_dbus_simple_array_property_getter(iter,
3304 							 DBUS_TYPE_OBJECT_PATH,
3305 							 paths, num, error);
3306 
3307 out:
3308 	while (i)
3309 		os_free(paths[--i]);
3310 	os_free(paths);
3311 	return success;
3312 }
3313 
3314 
3315 /**
3316  * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
3317  * @iter: Pointer to incoming dbus message iter
3318  * @error: Location to store error on failure
3319  * @user_data: Function specific data
3320  * Returns: A dbus message containing the PKCS #11 engine path
3321  *
3322  * Getter for "PKCS11EnginePath" property.
3323  */
wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter * iter,DBusError * error,void * user_data)3324 dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
3325 						DBusError *error,
3326 						void *user_data)
3327 {
3328 	struct wpa_supplicant *wpa_s = user_data;
3329 	const char *pkcs11_engine_path;
3330 
3331 	if (wpa_s->conf == NULL) {
3332 		wpa_printf(MSG_ERROR,
3333 			   "wpas_dbus_getter_pkcs11_engine_path[dbus]: An "
3334 			   "error occurred getting the PKCS #11 engine path.");
3335 		dbus_set_error_const(
3336 			error, DBUS_ERROR_FAILED,
3337 			"An error occured getting the PKCS #11 engine path.");
3338 		return FALSE;
3339 	}
3340 
3341 	if (wpa_s->conf->pkcs11_engine_path == NULL)
3342 		pkcs11_engine_path = "";
3343 	else
3344 		pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
3345 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3346 						&pkcs11_engine_path, error);
3347 }
3348 
3349 
3350 /**
3351  * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
3352  * @iter: Pointer to incoming dbus message iter
3353  * @error: Location to store error on failure
3354  * @user_data: Function specific data
3355  * Returns: A dbus message containing the PKCS #11 module path
3356  *
3357  * Getter for "PKCS11ModulePath" property.
3358  */
wpas_dbus_getter_pkcs11_module_path(DBusMessageIter * iter,DBusError * error,void * user_data)3359 dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
3360 						DBusError *error,
3361 						void *user_data)
3362 {
3363 	struct wpa_supplicant *wpa_s = user_data;
3364 	const char *pkcs11_module_path;
3365 
3366 	if (wpa_s->conf == NULL) {
3367 		wpa_printf(MSG_ERROR,
3368 			   "wpas_dbus_getter_pkcs11_module_path[dbus]: An "
3369 			   "error occurred getting the PKCS #11 module path.");
3370 		dbus_set_error_const(
3371 			error, DBUS_ERROR_FAILED,
3372 			"An error occured getting the PKCS #11 module path.");
3373 		return FALSE;
3374 	}
3375 
3376 	if (wpa_s->conf->pkcs11_module_path == NULL)
3377 		pkcs11_module_path = "";
3378 	else
3379 		pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
3380 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3381 						&pkcs11_module_path, error);
3382 }
3383 
3384 
3385 /**
3386  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
3387  * @iter: Pointer to incoming dbus message iter
3388  * @error: Location to store error on failure
3389  * @user_data: Function specific data
3390  * Returns: TRUE on success, FALSE on failure
3391  *
3392  * Getter for "Blobs" property.
3393  */
wpas_dbus_getter_blobs(DBusMessageIter * iter,DBusError * error,void * user_data)3394 dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
3395 				   void *user_data)
3396 {
3397 	struct wpa_supplicant *wpa_s = user_data;
3398 	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
3399 	struct wpa_config_blob *blob;
3400 
3401 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3402 					      "a{say}", &variant_iter) ||
3403 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
3404 					      "{say}", &dict_iter)) {
3405 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3406 		return FALSE;
3407 	}
3408 
3409 	blob = wpa_s->conf->blobs;
3410 	while (blob) {
3411 		if (!dbus_message_iter_open_container(&dict_iter,
3412 						      DBUS_TYPE_DICT_ENTRY,
3413 						      NULL, &entry_iter) ||
3414 		    !dbus_message_iter_append_basic(&entry_iter,
3415 						    DBUS_TYPE_STRING,
3416 						    &(blob->name)) ||
3417 		    !dbus_message_iter_open_container(&entry_iter,
3418 						      DBUS_TYPE_ARRAY,
3419 						      DBUS_TYPE_BYTE_AS_STRING,
3420 						      &array_iter) ||
3421 		    !dbus_message_iter_append_fixed_array(&array_iter,
3422 							  DBUS_TYPE_BYTE,
3423 							  &(blob->data),
3424 							  blob->len) ||
3425 		    !dbus_message_iter_close_container(&entry_iter,
3426 						       &array_iter) ||
3427 		    !dbus_message_iter_close_container(&dict_iter,
3428 						       &entry_iter)) {
3429 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3430 					     "no memory");
3431 			return FALSE;
3432 		}
3433 
3434 		blob = blob->next;
3435 	}
3436 
3437 	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
3438 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
3439 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3440 		return FALSE;
3441 	}
3442 
3443 	return TRUE;
3444 }
3445 
3446 
get_bss_helper(struct bss_handler_args * args,DBusError * error,const char * func_name)3447 static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
3448 				       DBusError *error, const char *func_name)
3449 {
3450 	struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
3451 
3452 	if (!res) {
3453 		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
3454 		           func_name, args->id);
3455 		dbus_set_error(error, DBUS_ERROR_FAILED,
3456 			       "%s: BSS %d not found",
3457 			       func_name, args->id);
3458 	}
3459 
3460 	return res;
3461 }
3462 
3463 
3464 /**
3465  * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
3466  * @iter: Pointer to incoming dbus message iter
3467  * @error: Location to store error on failure
3468  * @user_data: Function specific data
3469  * Returns: TRUE on success, FALSE on failure
3470  *
3471  * Getter for "BSSID" property.
3472  */
wpas_dbus_getter_bss_bssid(DBusMessageIter * iter,DBusError * error,void * user_data)3473 dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
3474 				       void *user_data)
3475 {
3476 	struct bss_handler_args *args = user_data;
3477 	struct wpa_bss *res;
3478 
3479 	res = get_bss_helper(args, error, __func__);
3480 	if (!res)
3481 		return FALSE;
3482 
3483 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3484 						      res->bssid, ETH_ALEN,
3485 						      error);
3486 }
3487 
3488 
3489 /**
3490  * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
3491  * @iter: Pointer to incoming dbus message iter
3492  * @error: Location to store error on failure
3493  * @user_data: Function specific data
3494  * Returns: TRUE on success, FALSE on failure
3495  *
3496  * Getter for "SSID" property.
3497  */
wpas_dbus_getter_bss_ssid(DBusMessageIter * iter,DBusError * error,void * user_data)3498 dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
3499 				      void *user_data)
3500 {
3501 	struct bss_handler_args *args = user_data;
3502 	struct wpa_bss *res;
3503 
3504 	res = get_bss_helper(args, error, __func__);
3505 	if (!res)
3506 		return FALSE;
3507 
3508 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3509 						      res->ssid, res->ssid_len,
3510 						      error);
3511 }
3512 
3513 
3514 /**
3515  * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
3516  * @iter: Pointer to incoming dbus message iter
3517  * @error: Location to store error on failure
3518  * @user_data: Function specific data
3519  * Returns: TRUE on success, FALSE on failure
3520  *
3521  * Getter for "Privacy" property.
3522  */
wpas_dbus_getter_bss_privacy(DBusMessageIter * iter,DBusError * error,void * user_data)3523 dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
3524 					 DBusError *error, void *user_data)
3525 {
3526 	struct bss_handler_args *args = user_data;
3527 	struct wpa_bss *res;
3528 	dbus_bool_t privacy;
3529 
3530 	res = get_bss_helper(args, error, __func__);
3531 	if (!res)
3532 		return FALSE;
3533 
3534 	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
3535 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3536 						&privacy, error);
3537 }
3538 
3539 
3540 /**
3541  * wpas_dbus_getter_bss_mode - Return the mode of a BSS
3542  * @iter: Pointer to incoming dbus message iter
3543  * @error: Location to store error on failure
3544  * @user_data: Function specific data
3545  * Returns: TRUE on success, FALSE on failure
3546  *
3547  * Getter for "Mode" property.
3548  */
wpas_dbus_getter_bss_mode(DBusMessageIter * iter,DBusError * error,void * user_data)3549 dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
3550 				      void *user_data)
3551 {
3552 	struct bss_handler_args *args = user_data;
3553 	struct wpa_bss *res;
3554 	const char *mode;
3555 
3556 	res = get_bss_helper(args, error, __func__);
3557 	if (!res)
3558 		return FALSE;
3559 	if (bss_is_dmg(res)) {
3560 		switch (res->caps & IEEE80211_CAP_DMG_MASK) {
3561 		case IEEE80211_CAP_DMG_PBSS:
3562 		case IEEE80211_CAP_DMG_IBSS:
3563 			mode = "ad-hoc";
3564 			break;
3565 		case IEEE80211_CAP_DMG_AP:
3566 			mode = "infrastructure";
3567 			break;
3568 		}
3569 	} else {
3570 		if (res->caps & IEEE80211_CAP_IBSS)
3571 			mode = "ad-hoc";
3572 		else
3573 			mode = "infrastructure";
3574 	}
3575 
3576 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3577 						&mode, error);
3578 }
3579 
3580 
3581 /**
3582  * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
3583  * @iter: Pointer to incoming dbus message iter
3584  * @error: Location to store error on failure
3585  * @user_data: Function specific data
3586  * Returns: TRUE on success, FALSE on failure
3587  *
3588  * Getter for "Level" property.
3589  */
wpas_dbus_getter_bss_signal(DBusMessageIter * iter,DBusError * error,void * user_data)3590 dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
3591 					DBusError *error, void *user_data)
3592 {
3593 	struct bss_handler_args *args = user_data;
3594 	struct wpa_bss *res;
3595 	s16 level;
3596 
3597 	res = get_bss_helper(args, error, __func__);
3598 	if (!res)
3599 		return FALSE;
3600 
3601 	level = (s16) res->level;
3602 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
3603 						&level, error);
3604 }
3605 
3606 
3607 /**
3608  * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
3609  * @iter: Pointer to incoming dbus message iter
3610  * @error: Location to store error on failure
3611  * @user_data: Function specific data
3612  * Returns: TRUE on success, FALSE on failure
3613  *
3614  * Getter for "Frequency" property.
3615  */
wpas_dbus_getter_bss_frequency(DBusMessageIter * iter,DBusError * error,void * user_data)3616 dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
3617 					   DBusError *error, void *user_data)
3618 {
3619 	struct bss_handler_args *args = user_data;
3620 	struct wpa_bss *res;
3621 	u16 freq;
3622 
3623 	res = get_bss_helper(args, error, __func__);
3624 	if (!res)
3625 		return FALSE;
3626 
3627 	freq = (u16) res->freq;
3628 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
3629 						&freq, error);
3630 }
3631 
3632 
cmp_u8s_desc(const void * a,const void * b)3633 static int cmp_u8s_desc(const void *a, const void *b)
3634 {
3635 	return (*(u8 *) b - *(u8 *) a);
3636 }
3637 
3638 
3639 /**
3640  * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
3641  * @iter: Pointer to incoming dbus message iter
3642  * @error: Location to store error on failure
3643  * @user_data: Function specific data
3644  * Returns: TRUE on success, FALSE on failure
3645  *
3646  * Getter for "Rates" property.
3647  */
wpas_dbus_getter_bss_rates(DBusMessageIter * iter,DBusError * error,void * user_data)3648 dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
3649 				       DBusError *error, void *user_data)
3650 {
3651 	struct bss_handler_args *args = user_data;
3652 	struct wpa_bss *res;
3653 	u8 *ie_rates = NULL;
3654 	u32 *real_rates;
3655 	int rates_num, i;
3656 	dbus_bool_t success = FALSE;
3657 
3658 	res = get_bss_helper(args, error, __func__);
3659 	if (!res)
3660 		return FALSE;
3661 
3662 	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
3663 	if (rates_num < 0)
3664 		return FALSE;
3665 
3666 	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
3667 
3668 	real_rates = os_malloc(sizeof(u32) * rates_num);
3669 	if (!real_rates) {
3670 		os_free(ie_rates);
3671 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3672 		return FALSE;
3673 	}
3674 
3675 	for (i = 0; i < rates_num; i++)
3676 		real_rates[i] = ie_rates[i] * 500000;
3677 
3678 	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
3679 							 real_rates, rates_num,
3680 							 error);
3681 
3682 	os_free(ie_rates);
3683 	os_free(real_rates);
3684 	return success;
3685 }
3686 
3687 
wpas_dbus_get_bss_security_prop(DBusMessageIter * iter,struct wpa_ie_data * ie_data,DBusError * error)3688 static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
3689 						   struct wpa_ie_data *ie_data,
3690 						   DBusError *error)
3691 {
3692 	DBusMessageIter iter_dict, variant_iter;
3693 	const char *group;
3694 	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
3695 	const char *key_mgmt[7]; /* max 7 key managements may be supported */
3696 	int n;
3697 
3698 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3699 					      "a{sv}", &variant_iter))
3700 		goto nomem;
3701 
3702 	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3703 		goto nomem;
3704 
3705 	/* KeyMgmt */
3706 	n = 0;
3707 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
3708 		key_mgmt[n++] = "wpa-psk";
3709 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
3710 		key_mgmt[n++] = "wpa-ft-psk";
3711 	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
3712 		key_mgmt[n++] = "wpa-psk-sha256";
3713 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
3714 		key_mgmt[n++] = "wpa-eap";
3715 	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
3716 		key_mgmt[n++] = "wpa-ft-eap";
3717 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
3718 		key_mgmt[n++] = "wpa-eap-sha256";
3719 	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
3720 		key_mgmt[n++] = "wpa-none";
3721 
3722 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
3723 					       key_mgmt, n))
3724 		goto nomem;
3725 
3726 	/* Group */
3727 	switch (ie_data->group_cipher) {
3728 	case WPA_CIPHER_WEP40:
3729 		group = "wep40";
3730 		break;
3731 	case WPA_CIPHER_TKIP:
3732 		group = "tkip";
3733 		break;
3734 	case WPA_CIPHER_CCMP:
3735 		group = "ccmp";
3736 		break;
3737 	case WPA_CIPHER_GCMP:
3738 		group = "gcmp";
3739 		break;
3740 	case WPA_CIPHER_WEP104:
3741 		group = "wep104";
3742 		break;
3743 	case WPA_CIPHER_CCMP_256:
3744 		group = "ccmp-256";
3745 		break;
3746 	case WPA_CIPHER_GCMP_256:
3747 		group = "gcmp-256";
3748 		break;
3749 	default:
3750 		group = "";
3751 		break;
3752 	}
3753 
3754 	if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
3755 		goto nomem;
3756 
3757 	/* Pairwise */
3758 	n = 0;
3759 	if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
3760 		pairwise[n++] = "tkip";
3761 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
3762 		pairwise[n++] = "ccmp";
3763 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
3764 		pairwise[n++] = "gcmp";
3765 	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
3766 		pairwise[n++] = "ccmp-256";
3767 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
3768 		pairwise[n++] = "gcmp-256";
3769 
3770 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
3771 					       pairwise, n))
3772 		goto nomem;
3773 
3774 	/* Management group (RSN only) */
3775 	if (ie_data->proto == WPA_PROTO_RSN) {
3776 		switch (ie_data->mgmt_group_cipher) {
3777 #ifdef CONFIG_IEEE80211W
3778 		case WPA_CIPHER_AES_128_CMAC:
3779 			group = "aes128cmac";
3780 			break;
3781 #endif /* CONFIG_IEEE80211W */
3782 		default:
3783 			group = "";
3784 			break;
3785 		}
3786 
3787 		if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
3788 						 group))
3789 			goto nomem;
3790 	}
3791 
3792 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
3793 		goto nomem;
3794 	if (!dbus_message_iter_close_container(iter, &variant_iter))
3795 		goto nomem;
3796 
3797 	return TRUE;
3798 
3799 nomem:
3800 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3801 	return FALSE;
3802 }
3803 
3804 
3805 /**
3806  * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
3807  * @iter: Pointer to incoming dbus message iter
3808  * @error: Location to store error on failure
3809  * @user_data: Function specific data
3810  * Returns: TRUE on success, FALSE on failure
3811  *
3812  * Getter for "WPA" property.
3813  */
wpas_dbus_getter_bss_wpa(DBusMessageIter * iter,DBusError * error,void * user_data)3814 dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
3815 				     void *user_data)
3816 {
3817 	struct bss_handler_args *args = user_data;
3818 	struct wpa_bss *res;
3819 	struct wpa_ie_data wpa_data;
3820 	const u8 *ie;
3821 
3822 	res = get_bss_helper(args, error, __func__);
3823 	if (!res)
3824 		return FALSE;
3825 
3826 	os_memset(&wpa_data, 0, sizeof(wpa_data));
3827 	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
3828 	if (ie) {
3829 		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3830 			dbus_set_error_const(error, DBUS_ERROR_FAILED,
3831 					     "failed to parse WPA IE");
3832 			return FALSE;
3833 		}
3834 	}
3835 
3836 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3837 }
3838 
3839 
3840 /**
3841  * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
3842  * @iter: Pointer to incoming dbus message iter
3843  * @error: Location to store error on failure
3844  * @user_data: Function specific data
3845  * Returns: TRUE on success, FALSE on failure
3846  *
3847  * Getter for "RSN" property.
3848  */
wpas_dbus_getter_bss_rsn(DBusMessageIter * iter,DBusError * error,void * user_data)3849 dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
3850 				     void *user_data)
3851 {
3852 	struct bss_handler_args *args = user_data;
3853 	struct wpa_bss *res;
3854 	struct wpa_ie_data wpa_data;
3855 	const u8 *ie;
3856 
3857 	res = get_bss_helper(args, error, __func__);
3858 	if (!res)
3859 		return FALSE;
3860 
3861 	os_memset(&wpa_data, 0, sizeof(wpa_data));
3862 	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
3863 	if (ie) {
3864 		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
3865 			dbus_set_error_const(error, DBUS_ERROR_FAILED,
3866 					     "failed to parse RSN IE");
3867 			return FALSE;
3868 		}
3869 	}
3870 
3871 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
3872 }
3873 
3874 
3875 /**
3876  * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
3877  * @iter: Pointer to incoming dbus message iter
3878  * @error: Location to store error on failure
3879  * @user_data: Function specific data
3880  * Returns: TRUE on success, FALSE on failure
3881  *
3882  * Getter for "WPS" property.
3883  */
wpas_dbus_getter_bss_wps(DBusMessageIter * iter,DBusError * error,void * user_data)3884 dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
3885 				     void *user_data)
3886 {
3887 	struct bss_handler_args *args = user_data;
3888 	struct wpa_bss *res;
3889 #ifdef CONFIG_WPS
3890 	struct wpabuf *wps_ie;
3891 #endif /* CONFIG_WPS */
3892 	DBusMessageIter iter_dict, variant_iter;
3893 	const char *type = "";
3894 
3895 	res = get_bss_helper(args, error, __func__);
3896 	if (!res)
3897 		return FALSE;
3898 
3899 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3900 					      "a{sv}", &variant_iter))
3901 		goto nomem;
3902 
3903 	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
3904 		goto nomem;
3905 
3906 #ifdef CONFIG_WPS
3907 	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
3908 	if (wps_ie) {
3909 		if (wps_is_selected_pbc_registrar(wps_ie))
3910 			type = "pbc";
3911 		else if (wps_is_selected_pin_registrar(wps_ie))
3912 			type = "pin";
3913 	}
3914 #endif /* CONFIG_WPS */
3915 
3916 	if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
3917 		goto nomem;
3918 
3919 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
3920 		goto nomem;
3921 	if (!dbus_message_iter_close_container(iter, &variant_iter))
3922 		goto nomem;
3923 
3924 	return TRUE;
3925 
3926 nomem:
3927 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3928 	return FALSE;
3929 }
3930 
3931 
3932 /**
3933  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
3934  * @iter: Pointer to incoming dbus message iter
3935  * @error: Location to store error on failure
3936  * @user_data: Function specific data
3937  * Returns: TRUE on success, FALSE on failure
3938  *
3939  * Getter for "IEs" property.
3940  */
wpas_dbus_getter_bss_ies(DBusMessageIter * iter,DBusError * error,void * user_data)3941 dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
3942 				     void *user_data)
3943 {
3944 	struct bss_handler_args *args = user_data;
3945 	struct wpa_bss *res;
3946 
3947 	res = get_bss_helper(args, error, __func__);
3948 	if (!res)
3949 		return FALSE;
3950 
3951 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
3952 						      res + 1, res->ie_len,
3953 						      error);
3954 }
3955 
3956 
3957 /**
3958  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
3959  * @iter: Pointer to incoming dbus message iter
3960  * @error: Location to store error on failure
3961  * @user_data: Function specific data
3962  * Returns: TRUE on success, FALSE on failure
3963  *
3964  * Getter for "enabled" property of a configured network.
3965  */
wpas_dbus_getter_enabled(DBusMessageIter * iter,DBusError * error,void * user_data)3966 dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
3967 				     void *user_data)
3968 {
3969 	struct network_handler_args *net = user_data;
3970 	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
3971 
3972 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3973 						&enabled, error);
3974 }
3975 
3976 
3977 /**
3978  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
3979  * @iter: Pointer to incoming dbus message iter
3980  * @error: Location to store error on failure
3981  * @user_data: Function specific data
3982  * Returns: TRUE on success, FALSE on failure
3983  *
3984  * Setter for "Enabled" property of a configured network.
3985  */
wpas_dbus_setter_enabled(DBusMessageIter * iter,DBusError * error,void * user_data)3986 dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
3987 				     void *user_data)
3988 {
3989 	struct network_handler_args *net = user_data;
3990 	struct wpa_supplicant *wpa_s;
3991 	struct wpa_ssid *ssid;
3992 	dbus_bool_t enable;
3993 
3994 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
3995 					      &enable))
3996 		return FALSE;
3997 
3998 	wpa_s = net->wpa_s;
3999 	ssid = net->ssid;
4000 
4001 	if (enable)
4002 		wpa_supplicant_enable_network(wpa_s, ssid);
4003 	else
4004 		wpa_supplicant_disable_network(wpa_s, ssid);
4005 
4006 	return TRUE;
4007 }
4008 
4009 
4010 /**
4011  * wpas_dbus_getter_network_properties - Get options for a configured network
4012  * @iter: Pointer to incoming dbus message iter
4013  * @error: Location to store error on failure
4014  * @user_data: Function specific data
4015  * Returns: TRUE on success, FALSE on failure
4016  *
4017  * Getter for "Properties" property of a configured network.
4018  */
wpas_dbus_getter_network_properties(DBusMessageIter * iter,DBusError * error,void * user_data)4019 dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
4020 						DBusError *error,
4021 						void *user_data)
4022 {
4023 	struct network_handler_args *net = user_data;
4024 	DBusMessageIter	variant_iter, dict_iter;
4025 	char **iterator;
4026 	char **props = wpa_config_get_all(net->ssid, 1);
4027 	dbus_bool_t success = FALSE;
4028 
4029 	if (!props) {
4030 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4031 		return FALSE;
4032 	}
4033 
4034 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
4035 					      &variant_iter) ||
4036 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
4037 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4038 		goto out;
4039 	}
4040 
4041 	iterator = props;
4042 	while (*iterator) {
4043 		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
4044 						 *(iterator + 1))) {
4045 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4046 					     "no memory");
4047 			goto out;
4048 		}
4049 		iterator += 2;
4050 	}
4051 
4052 
4053 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
4054 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
4055 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4056 		goto out;
4057 	}
4058 
4059 	success = TRUE;
4060 
4061 out:
4062 	iterator = props;
4063 	while (*iterator) {
4064 		os_free(*iterator);
4065 		iterator++;
4066 	}
4067 	os_free(props);
4068 	return success;
4069 }
4070 
4071 
4072 /**
4073  * wpas_dbus_setter_network_properties - Set options for a configured network
4074  * @iter: Pointer to incoming dbus message iter
4075  * @error: Location to store error on failure
4076  * @user_data: Function specific data
4077  * Returns: TRUE on success, FALSE on failure
4078  *
4079  * Setter for "Properties" property of a configured network.
4080  */
wpas_dbus_setter_network_properties(DBusMessageIter * iter,DBusError * error,void * user_data)4081 dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
4082 						DBusError *error,
4083 						void *user_data)
4084 {
4085 	struct network_handler_args *net = user_data;
4086 	struct wpa_ssid *ssid = net->ssid;
4087 	DBusMessageIter	variant_iter;
4088 
4089 	dbus_message_iter_recurse(iter, &variant_iter);
4090 	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
4091 }
4092 
4093 
4094 #ifdef CONFIG_AP
4095 
wpas_dbus_handler_subscribe_preq(DBusMessage * message,struct wpa_supplicant * wpa_s)4096 DBusMessage * wpas_dbus_handler_subscribe_preq(
4097 	DBusMessage *message, struct wpa_supplicant *wpa_s)
4098 {
4099 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4100 	char *name;
4101 
4102 	if (wpa_s->preq_notify_peer != NULL) {
4103 		if (os_strcmp(dbus_message_get_sender(message),
4104 			      wpa_s->preq_notify_peer) == 0)
4105 			return NULL;
4106 
4107 		return dbus_message_new_error(message,
4108 			WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
4109 			"Another application is already subscribed");
4110 	}
4111 
4112 	name = os_strdup(dbus_message_get_sender(message));
4113 	if (!name)
4114 		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
4115 					      "out of memory");
4116 
4117 	wpa_s->preq_notify_peer = name;
4118 
4119 	/* Subscribe to clean up if application closes socket */
4120 	wpas_dbus_subscribe_noc(priv);
4121 
4122 	/*
4123 	 * Double-check it's still alive to make sure that we didn't
4124 	 * miss the NameOwnerChanged signal, e.g. while strdup'ing.
4125 	 */
4126 	if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
4127 		/*
4128 		 * Application no longer exists, clean up.
4129 		 * The return value is irrelevant now.
4130 		 *
4131 		 * Need to check if the NameOwnerChanged handling
4132 		 * already cleaned up because we have processed
4133 		 * DBus messages while checking if the name still
4134 		 * has an owner.
4135 		 */
4136 		if (!wpa_s->preq_notify_peer)
4137 			return NULL;
4138 		os_free(wpa_s->preq_notify_peer);
4139 		wpa_s->preq_notify_peer = NULL;
4140 		wpas_dbus_unsubscribe_noc(priv);
4141 	}
4142 
4143 	return NULL;
4144 }
4145 
4146 
wpas_dbus_handler_unsubscribe_preq(DBusMessage * message,struct wpa_supplicant * wpa_s)4147 DBusMessage * wpas_dbus_handler_unsubscribe_preq(
4148 	DBusMessage *message, struct wpa_supplicant *wpa_s)
4149 {
4150 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4151 
4152 	if (!wpa_s->preq_notify_peer)
4153 		return dbus_message_new_error(message,
4154 			WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
4155 			"Not subscribed");
4156 
4157 	if (os_strcmp(wpa_s->preq_notify_peer,
4158 		      dbus_message_get_sender(message)))
4159 		return dbus_message_new_error(message,
4160 			WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
4161 			"Can't unsubscribe others");
4162 
4163 	os_free(wpa_s->preq_notify_peer);
4164 	wpa_s->preq_notify_peer = NULL;
4165 	wpas_dbus_unsubscribe_noc(priv);
4166 	return NULL;
4167 }
4168 
4169 
wpas_dbus_signal_preq(struct wpa_supplicant * wpa_s,const u8 * addr,const u8 * dst,const u8 * bssid,const u8 * ie,size_t ie_len,u32 ssi_signal)4170 void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
4171 			   const u8 *addr, const u8 *dst, const u8 *bssid,
4172 			   const u8 *ie, size_t ie_len, u32 ssi_signal)
4173 {
4174 	DBusMessage *msg;
4175 	DBusMessageIter iter, dict_iter;
4176 	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4177 
4178 	/* Do nothing if the control interface is not turned on */
4179 	if (priv == NULL)
4180 		return;
4181 
4182 	if (wpa_s->preq_notify_peer == NULL)
4183 		return;
4184 
4185 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
4186 				      WPAS_DBUS_NEW_IFACE_INTERFACE,
4187 				      "ProbeRequest");
4188 	if (msg == NULL)
4189 		return;
4190 
4191 	dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
4192 
4193 	dbus_message_iter_init_append(msg, &iter);
4194 
4195 	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
4196 		goto fail;
4197 	if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
4198 						     (const char *) addr,
4199 						     ETH_ALEN))
4200 		goto fail;
4201 	if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
4202 						    (const char *) dst,
4203 						    ETH_ALEN))
4204 		goto fail;
4205 	if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
4206 						      (const char *) bssid,
4207 						      ETH_ALEN))
4208 		goto fail;
4209 	if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
4210 							     (const char *) ie,
4211 							     ie_len))
4212 		goto fail;
4213 	if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
4214 						      ssi_signal))
4215 		goto fail;
4216 	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
4217 		goto fail;
4218 
4219 	dbus_connection_send(priv->con, msg, NULL);
4220 	goto out;
4221 fail:
4222 	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
4223 out:
4224 	dbus_message_unref(msg);
4225 }
4226 
4227 #endif /* CONFIG_AP */
4228