]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/dbus/dbus_new_handlers.c
Remove CONFIG_IEEE80211W build parameter
[thirdparty/hostap.git] / wpa_supplicant / dbus / dbus_new_handlers.c
CommitLineData
8fc2fb56
WS
1/*
2 * WPA Supplicant / dbus-based control interface
3 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
7899e2f4 4 * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
5e3b5197 5 * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
8fc2fb56 6 *
c5a3cebf
JM
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
8fc2fb56
WS
9 */
10
11#include "includes.h"
12
13#include "common.h"
a206a29a
JM
14#include "common/ieee802_11_defs.h"
15#include "eap_peer/eap_methods.h"
16#include "eapol_supp/eapol_supp_sm.h"
7899e2f4 17#include "rsn_supp/wpa.h"
c3f23ad6
AS
18#include "ap/hostapd.h"
19#include "ap/sta_info.h"
20#include "ap/ap_drv_ops.h"
19b3211d
JM
21#include "../config.h"
22#include "../wpa_supplicant_i.h"
23#include "../driver_i.h"
19b3211d 24#include "../notify.h"
ccd286d0 25#include "../bss.h"
9ba9fa07 26#include "../scan.h"
7c865c68 27#include "../autoscan.h"
c3f23ad6 28#include "../ap.h"
a206a29a
JM
29#include "dbus_new_helpers.h"
30#include "dbus_new.h"
31#include "dbus_new_handlers.h"
32#include "dbus_dict_helpers.h"
2d43d37f 33#include "dbus_common_i.h"
7a4a93b9 34#include "drivers/driver.h"
190f6f11
SB
35#ifdef CONFIG_MESH
36#include "ap/hostapd.h"
37#include "ap/sta_info.h"
38#endif /* CONFIG_MESH */
8fc2fb56 39
38279bdb 40static const char * const debug_strings[] = {
14dc0011 41 "excessive", "msgdump", "debug", "info", "warning", "error", NULL
a2753c28
MH
42};
43
8fc2fb56 44
8fc2fb56 45/**
ff1d8104 46 * wpas_dbus_error_unknown_error - Return a new UnknownError error message
8fc2fb56
WS
47 * @message: Pointer to incoming dbus message this error refers to
48 * @arg: Optional string appended to error message
49 * Returns: a dbus error message
50 *
51 * Convenience function to create and return an UnknownError
52 */
36da1358
JM
53DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
54 const char *arg)
8fc2fb56 55{
5228401c
JM
56 return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
57 arg);
8fc2fb56
WS
58}
59
60
61/**
62 * wpas_dbus_error_iface_unknown - Return a new invalid interface error message
63 * @message: Pointer to incoming dbus message this error refers to
64 * Returns: A dbus error message
65 *
66 * Convenience function to create and return an invalid interface error
67 */
68static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
69{
38279bdb
JM
70 return dbus_message_new_error(
71 message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
72 "wpa_supplicant knows nothing about this interface.");
8fc2fb56
WS
73}
74
75
76/**
77 * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
78 * @message: Pointer to incoming dbus message this error refers to
79 * Returns: a dbus error message
80 *
81 * Convenience function to create and return an invalid network error
82 */
83static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
84{
38279bdb
JM
85 return dbus_message_new_error(
86 message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
87 "There is no such a network in this interface.");
8fc2fb56
WS
88}
89
90
91/**
db9a76c0 92 * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
8fc2fb56
WS
93 * @message: Pointer to incoming dbus message this error refers to
94 * Returns: a dbus error message
95 *
96 * Convenience function to create and return an invalid options error
97 */
db9a76c0 98DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
36da1358 99 const char *arg)
8fc2fb56
WS
100{
101 DBusMessage *reply;
102
38279bdb
JM
103 reply = dbus_message_new_error(
104 message, WPAS_DBUS_ERROR_INVALID_ARGS,
105 "Did not receive correct message arguments.");
8fc2fb56
WS
106 if (arg != NULL)
107 dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
108 DBUS_TYPE_INVALID);
109
110 return reply;
111}
112
113
e9b32dae 114/**
115 * wpas_dbus_error_scan_error - Return a new ScanError error message
116 * @message: Pointer to incoming dbus message this error refers to
117 * @error: Optional string to be used as the error message
118 * Returns: a dbus error message
119 *
120 * Convenience function to create and return a scan error
121 */
3cccf0b8
JM
122static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
123 const char *error)
e9b32dae 124{
3cccf0b8
JM
125 return dbus_message_new_error(message,
126 WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
127 error);
e9b32dae 128}
129
130
a0caebf3
JM
131DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
132{
133 wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
134 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
135}
136
137
38279bdb 138static const char * const dont_quote[] = {
8fc2fb56
WS
139 "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
140 "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
99276998 141 "bssid", "scan_freq", "freq_list", NULL
8fc2fb56
WS
142};
143
144static dbus_bool_t should_quote_opt(const char *key)
145{
146 int i = 0;
38279bdb 147
8fc2fb56 148 while (dont_quote[i] != NULL) {
5228401c 149 if (os_strcmp(key, dont_quote[i]) == 0)
8fc2fb56
WS
150 return FALSE;
151 i++;
152 }
153 return TRUE;
154}
155
8fc2fb56
WS
156/**
157 * get_iface_by_dbus_path - Get a new network interface
158 * @global: Pointer to global data from wpa_supplicant_init()
159 * @path: Pointer to a dbus object path representing an interface
160 * Returns: Pointer to the interface or %NULL if not found
161 */
162static struct wpa_supplicant * get_iface_by_dbus_path(
163 struct wpa_global *global, const char *path)
164{
165 struct wpa_supplicant *wpa_s;
166
167 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
8a78e227
JM
168 if (wpa_s->dbus_new_path &&
169 os_strcmp(wpa_s->dbus_new_path, path) == 0)
8fc2fb56
WS
170 return wpa_s;
171 }
172 return NULL;
173}
174
175
176/**
177 * set_network_properties - Set properties of a configured network
aa53509f 178 * @wpa_s: wpa_supplicant structure for a network interface
8fc2fb56
WS
179 * @ssid: wpa_ssid structure for a configured network
180 * @iter: DBus message iterator containing dictionary of network
181 * properties to set.
6aeeb6fa
DW
182 * @error: On failure, an error describing the failure
183 * Returns: TRUE if the request succeeds, FALSE if it failed
8fc2fb56
WS
184 *
185 * Sets network configuration with parameters given id DBus dictionary
186 */
6aeeb6fa
DW
187dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
188 struct wpa_ssid *ssid,
189 DBusMessageIter *iter,
190 DBusError *error)
8fc2fb56 191{
8fc2fb56 192 struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
8fc2fb56 193 DBusMessageIter iter_dict;
6aeeb6fa 194 char *value = NULL;
8fc2fb56 195
6aeeb6fa
DW
196 if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
197 return FALSE;
8fc2fb56
WS
198
199 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
8fc2fb56
WS
200 size_t size = 50;
201 int ret;
6aeeb6fa
DW
202
203 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
204 goto error;
205
206 value = NULL;
8fc2fb56 207 if (entry.type == DBUS_TYPE_ARRAY &&
5228401c 208 entry.array_type == DBUS_TYPE_BYTE) {
8fc2fb56
WS
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
5228401c
JM
217 ret = wpa_snprintf_hex(value, size,
218 (u8 *) entry.bytearray_value,
219 entry.array_len);
8fc2fb56
WS
220 if (ret <= 0)
221 goto error;
fae3a72f
JM
222 } else if (entry.type == DBUS_TYPE_STRING) {
223 if (should_quote_opt(entry.key)) {
224 size = os_strlen(entry.str_value);
c1a14ef4 225 if (size == 0)
fae3a72f
JM
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);
1f102d3b 235 if (os_snprintf_error(size, ret))
fae3a72f 236 goto error;
5228401c 237 } else {
fae3a72f
JM
238 value = os_strdup(entry.str_value);
239 if (value == NULL)
240 goto error;
8fc2fb56 241 }
fae3a72f
JM
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);
a9aaacbb 249 if (os_snprintf_error(size, ret))
fae3a72f
JM
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);
a9aaacbb 258 if (os_snprintf_error(size, ret))
fae3a72f
JM
259 goto error;
260 } else
261 goto error;
8fc2fb56
WS
262
263 if (wpa_config_set(ssid, entry.key, value, 0) < 0)
264 goto error;
265
98a4cd44
JM
266 if (os_strcmp(entry.key, "bssid") != 0 &&
267 os_strcmp(entry.key, "priority") != 0)
268 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
269
270 if (wpa_s->current_ssid == ssid ||
271 wpa_s->current_ssid == NULL) {
272 /*
273 * Invalidate the EAP session cache if anything in the
274 * current or previously used configuration changes.
275 */
276 eapol_sm_invalidate_cached_session(wpa_s->eapol);
277 }
278
5228401c
JM
279 if ((os_strcmp(entry.key, "psk") == 0 &&
280 value[0] == '"' && ssid->ssid_len) ||
024d018b 281 (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
8fc2fb56 282 wpa_config_update_psk(ssid);
aa53509f
DS
283 else if (os_strcmp(entry.key, "priority") == 0)
284 wpa_config_update_prio_list(wpa_s->conf);
8fc2fb56
WS
285
286 os_free(value);
ceb4cd89 287 value = NULL;
8fc2fb56 288 wpa_dbus_dict_entry_clear(&entry);
8fc2fb56 289 }
fae3a72f 290
6aeeb6fa
DW
291 return TRUE;
292
293error:
294 os_free(value);
295 wpa_dbus_dict_entry_clear(&entry);
296 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
297 "invalid message format");
298 return FALSE;
8fc2fb56
WS
299}
300
301
fcea0b7d
WS
302/**
303 * wpas_dbus_simple_property_getter - Get basic type property
6aeeb6fa 304 * @iter: Message iter to use when appending arguments
fcea0b7d
WS
305 * @type: DBus type of property (must be basic type)
306 * @val: pointer to place holding property value
6aeeb6fa
DW
307 * @error: On failure an error describing the failure
308 * Returns: TRUE if the request was successful, FALSE if it failed
fcea0b7d
WS
309 *
310 * Generic getter for basic type properties. Type is required to be basic.
311 */
6aeeb6fa
DW
312dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
313 const int type,
314 const void *val,
315 DBusError *error)
fcea0b7d 316{
6aeeb6fa 317 DBusMessageIter variant_iter;
fcea0b7d
WS
318
319 if (!dbus_type_is_basic(type)) {
6aeeb6fa 320 dbus_set_error(error, DBUS_ERROR_FAILED,
38279bdb 321 "%s: given type is not basic", __func__);
6aeeb6fa 322 return FALSE;
fcea0b7d
WS
323 }
324
6aeeb6fa 325 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
38279bdb
JM
326 wpa_dbus_type_as_string(type),
327 &variant_iter) ||
e3c4f0b5
JM
328 !dbus_message_iter_append_basic(&variant_iter, type, val) ||
329 !dbus_message_iter_close_container(iter, &variant_iter)) {
330 dbus_set_error(error, DBUS_ERROR_FAILED,
331 "%s: error constructing reply", __func__);
332 return FALSE;
333 }
6aeeb6fa
DW
334
335 return TRUE;
fcea0b7d
WS
336}
337
338
339/**
340 * wpas_dbus_simple_property_setter - Set basic type property
341 * @message: Pointer to incoming dbus message
342 * @type: DBus type of property (must be basic type)
343 * @val: pointer to place where value being set will be stored
6aeeb6fa 344 * Returns: TRUE if the request was successful, FALSE if it failed
fcea0b7d
WS
345 *
346 * Generic setter for basic type properties. Type is required to be basic.
347 */
6aeeb6fa
DW
348dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
349 DBusError *error,
350 const int type, void *val)
fcea0b7d 351{
6aeeb6fa 352 DBusMessageIter variant_iter;
fcea0b7d
WS
353
354 if (!dbus_type_is_basic(type)) {
6aeeb6fa
DW
355 dbus_set_error(error, DBUS_ERROR_FAILED,
356 "%s: given type is not basic", __func__);
357 return FALSE;
fcea0b7d
WS
358 }
359
6aeeb6fa
DW
360 /* Look at the new value */
361 dbus_message_iter_recurse(iter, &variant_iter);
fcea0b7d 362 if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
6aeeb6fa
DW
363 dbus_set_error_const(error, DBUS_ERROR_FAILED,
364 "wrong property type");
365 return FALSE;
fcea0b7d
WS
366 }
367 dbus_message_iter_get_basic(&variant_iter, val);
368
6aeeb6fa 369 return TRUE;
fcea0b7d
WS
370}
371
372
373/**
374 * wpas_dbus_simple_array_property_getter - Get array type property
6aeeb6fa 375 * @iter: Pointer to incoming dbus message iterator
fcea0b7d
WS
376 * @type: DBus type of property array elements (must be basic type)
377 * @array: pointer to array of elements to put into response message
378 * @array_len: length of above array
6aeeb6fa
DW
379 * @error: a pointer to an error to fill on failure
380 * Returns: TRUE if the request succeeded, FALSE if it failed
fcea0b7d
WS
381 *
382 * Generic getter for array type properties. Array elements type is
383 * required to be basic.
384 */
6aeeb6fa
DW
385dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
386 const int type,
387 const void *array,
388 size_t array_len,
389 DBusError *error)
fcea0b7d 390{
6aeeb6fa 391 DBusMessageIter variant_iter, array_iter;
fcea0b7d
WS
392 char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
393 const char *sub_type_str;
394 size_t element_size, i;
395
396 if (!dbus_type_is_basic(type)) {
6aeeb6fa 397 dbus_set_error(error, DBUS_ERROR_FAILED,
38279bdb 398 "%s: given type is not basic", __func__);
6aeeb6fa 399 return FALSE;
fcea0b7d
WS
400 }
401
97d3f8c3 402 sub_type_str = wpa_dbus_type_as_string(type);
fcea0b7d
WS
403 type_str[1] = sub_type_str[0];
404
6aeeb6fa 405 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
e3c4f0b5
JM
406 type_str, &variant_iter) ||
407 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
fcea0b7d 408 sub_type_str, &array_iter)) {
6aeeb6fa 409 dbus_set_error(error, DBUS_ERROR_FAILED,
e3c4f0b5 410 "%s: failed to construct message", __func__);
6aeeb6fa 411 return FALSE;
fcea0b7d
WS
412 }
413
38279bdb 414 switch (type) {
fcea0b7d
WS
415 case DBUS_TYPE_BYTE:
416 case DBUS_TYPE_BOOLEAN:
417 element_size = 1;
418 break;
419 case DBUS_TYPE_INT16:
420 case DBUS_TYPE_UINT16:
421 element_size = sizeof(uint16_t);
422 break;
423 case DBUS_TYPE_INT32:
424 case DBUS_TYPE_UINT32:
425 element_size = sizeof(uint32_t);
426 break;
427 case DBUS_TYPE_INT64:
428 case DBUS_TYPE_UINT64:
429 element_size = sizeof(uint64_t);
430 break;
431 case DBUS_TYPE_DOUBLE:
432 element_size = sizeof(double);
433 break;
434 case DBUS_TYPE_STRING:
435 case DBUS_TYPE_OBJECT_PATH:
436 element_size = sizeof(char *);
437 break;
438 default:
6aeeb6fa 439 dbus_set_error(error, DBUS_ERROR_FAILED,
38279bdb 440 "%s: unknown element type %d", __func__, type);
6aeeb6fa 441 return FALSE;
fcea0b7d
WS
442 }
443
444 for (i = 0; i < array_len; i++) {
25be28a3 445 if (!dbus_message_iter_append_basic(&array_iter, type,
07e36539
ST
446 (const char *) array +
447 i * element_size)) {
25be28a3
JM
448 dbus_set_error(error, DBUS_ERROR_FAILED,
449 "%s: failed to construct message 2.5",
450 __func__);
451 return FALSE;
452 }
fcea0b7d
WS
453 }
454
e3c4f0b5
JM
455 if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
456 !dbus_message_iter_close_container(iter, &variant_iter)) {
6aeeb6fa 457 dbus_set_error(error, DBUS_ERROR_FAILED,
38279bdb 458 "%s: failed to construct message 3", __func__);
6aeeb6fa 459 return FALSE;
fcea0b7d
WS
460 }
461
96c4f3a7
JS
462 return TRUE;
463}
464
465
466/**
467 * wpas_dbus_simple_array_array_property_getter - Get array array type property
468 * @iter: Pointer to incoming dbus message iterator
469 * @type: DBus type of property array elements (must be basic type)
470 * @array: pointer to array of elements to put into response message
471 * @array_len: length of above array
472 * @error: a pointer to an error to fill on failure
473 * Returns: TRUE if the request succeeded, FALSE if it failed
474 *
475 * Generic getter for array type properties. Array elements type is
476 * required to be basic.
477 */
478dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
479 const int type,
480 struct wpabuf **array,
481 size_t array_len,
482 DBusError *error)
483{
484 DBusMessageIter variant_iter, array_iter;
485 char type_str[] = "aa?";
486 char inner_type_str[] = "a?";
487 const char *sub_type_str;
488 size_t i;
489
490 if (!dbus_type_is_basic(type)) {
491 dbus_set_error(error, DBUS_ERROR_FAILED,
492 "%s: given type is not basic", __func__);
493 return FALSE;
494 }
495
496 sub_type_str = wpa_dbus_type_as_string(type);
497 type_str[2] = sub_type_str[0];
498 inner_type_str[1] = sub_type_str[0];
499
500 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
e3c4f0b5
JM
501 type_str, &variant_iter) ||
502 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
96c4f3a7
JS
503 inner_type_str, &array_iter)) {
504 dbus_set_error(error, DBUS_ERROR_FAILED,
e3c4f0b5 505 "%s: failed to construct message", __func__);
96c4f3a7
JS
506 return FALSE;
507 }
508
010fc5f5 509 for (i = 0; i < array_len && array[i]; i++) {
96c4f3a7
JS
510 wpa_dbus_dict_bin_array_add_element(&array_iter,
511 wpabuf_head(array[i]),
512 wpabuf_len(array[i]));
513
514 }
515
e3c4f0b5
JM
516 if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
517 !dbus_message_iter_close_container(iter, &variant_iter)) {
96c4f3a7 518 dbus_set_error(error, DBUS_ERROR_FAILED,
e3c4f0b5 519 "%s: failed to close message", __func__);
6aeeb6fa
DW
520 return FALSE;
521 }
522
523 return TRUE;
fcea0b7d
WS
524}
525
526
77fcbf7f
JM
527/**
528 * wpas_dbus_string_property_getter - Get string type property
529 * @iter: Message iter to use when appending arguments
530 * @val: Pointer to place holding property value, can be %NULL
531 * @error: On failure an error describing the failure
532 * Returns: TRUE if the request was successful, FALSE if it failed
533 *
534 * Generic getter for string type properties. %NULL is converted to an empty
535 * string.
536 */
537dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter,
538 const void *val,
539 DBusError *error)
540{
541 if (!val)
542 val = "";
543 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
544 &val, error);
545}
546
547
8fc2fb56
WS
548/**
549 * wpas_dbus_handler_create_interface - Request registration of a network iface
550 * @message: Pointer to incoming dbus message
551 * @global: %wpa_supplicant global data structure
552 * Returns: The object path of the new interface object,
553 * or a dbus error message with more information
554 *
2f00ad44 555 * Handler function for "CreateInterface" method call. Handles requests
8fc2fb56
WS
556 * by dbus clients to register a network interface that wpa_supplicant
557 * will manage.
558 */
559DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
5228401c 560 struct wpa_global *global)
8fc2fb56 561{
8fc2fb56
WS
562 DBusMessageIter iter_dict;
563 DBusMessage *reply = NULL;
564 DBusMessageIter iter;
565 struct wpa_dbus_dict_entry entry;
2f00ad44
JM
566 char *driver = NULL;
567 char *ifname = NULL;
d4c1ec56 568 char *confname = NULL;
2f00ad44 569 char *bridge_ifname = NULL;
8fc2fb56
WS
570
571 dbus_message_iter_init(message, &iter);
572
6aeeb6fa 573 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
8fc2fb56
WS
574 goto error;
575 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
576 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
577 goto error;
38279bdb
JM
578 if (os_strcmp(entry.key, "Driver") == 0 &&
579 entry.type == DBUS_TYPE_STRING) {
beb9e117 580 os_free(driver);
2f00ad44
JM
581 driver = os_strdup(entry.str_value);
582 wpa_dbus_dict_entry_clear(&entry);
583 if (driver == NULL)
a354bcc8 584 goto oom;
38279bdb
JM
585 } else if (os_strcmp(entry.key, "Ifname") == 0 &&
586 entry.type == DBUS_TYPE_STRING) {
beb9e117 587 os_free(ifname);
2f00ad44
JM
588 ifname = os_strdup(entry.str_value);
589 wpa_dbus_dict_entry_clear(&entry);
590 if (ifname == NULL)
a354bcc8 591 goto oom;
38279bdb
JM
592 } else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
593 entry.type == DBUS_TYPE_STRING) {
beb9e117 594 os_free(confname);
d4c1ec56
SL
595 confname = os_strdup(entry.str_value);
596 wpa_dbus_dict_entry_clear(&entry);
597 if (confname == NULL)
a354bcc8 598 goto oom;
38279bdb
JM
599 } else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
600 entry.type == DBUS_TYPE_STRING) {
beb9e117 601 os_free(bridge_ifname);
2f00ad44
JM
602 bridge_ifname = os_strdup(entry.str_value);
603 wpa_dbus_dict_entry_clear(&entry);
604 if (bridge_ifname == NULL)
a354bcc8 605 goto oom;
5228401c 606 } else {
8fc2fb56
WS
607 wpa_dbus_dict_entry_clear(&entry);
608 goto error;
609 }
8fc2fb56
WS
610 }
611
2f00ad44
JM
612 if (ifname == NULL)
613 goto error; /* Required Ifname argument missing */
614
8fc2fb56
WS
615 /*
616 * Try to get the wpa_supplicant record for this iface, return
617 * an error if we already control it.
618 */
2f00ad44 619 if (wpa_supplicant_get_iface(global, ifname) != NULL) {
38279bdb
JM
620 reply = dbus_message_new_error(
621 message, WPAS_DBUS_ERROR_IFACE_EXISTS,
622 "wpa_supplicant already controls this interface.");
8fc2fb56
WS
623 } else {
624 struct wpa_supplicant *wpa_s;
2f00ad44 625 struct wpa_interface iface;
38279bdb 626
2f00ad44
JM
627 os_memset(&iface, 0, sizeof(iface));
628 iface.driver = driver;
629 iface.ifname = ifname;
d4c1ec56 630 iface.confname = confname;
2f00ad44 631 iface.bridge_ifname = bridge_ifname;
8fc2fb56 632 /* Otherwise, have wpa_supplicant attach to it. */
1772d348 633 wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
8a78e227 634 if (wpa_s && wpa_s->dbus_new_path) {
c49cf2d6 635 const char *path = wpa_s->dbus_new_path;
38279bdb 636
8fc2fb56
WS
637 reply = dbus_message_new_method_return(message);
638 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
38279bdb 639 &path, DBUS_TYPE_INVALID);
8fc2fb56 640 } else {
5228401c 641 reply = wpas_dbus_error_unknown_error(
38279bdb
JM
642 message,
643 "wpa_supplicant couldn't grab this interface.");
8fc2fb56
WS
644 }
645 }
2f00ad44
JM
646
647out:
648 os_free(driver);
649 os_free(ifname);
21270bb4 650 os_free(confname);
2f00ad44 651 os_free(bridge_ifname);
8fc2fb56
WS
652 return reply;
653
654error:
db9a76c0 655 reply = wpas_dbus_error_invalid_args(message, NULL);
2f00ad44 656 goto out;
a354bcc8
JM
657oom:
658 reply = wpas_dbus_error_no_memory(message);
659 goto out;
8fc2fb56
WS
660}
661
662
663/**
664 * wpas_dbus_handler_remove_interface - Request deregistration of an interface
665 * @message: Pointer to incoming dbus message
666 * @global: wpa_supplicant global data structure
667 * Returns: a dbus message containing a UINT32 indicating success (1) or
668 * failure (0), or returns a dbus error message with more information
669 *
670 * Handler function for "removeInterface" method call. Handles requests
671 * by dbus clients to deregister a network interface that wpa_supplicant
672 * currently manages.
673 */
674DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
5228401c 675 struct wpa_global *global)
8fc2fb56
WS
676{
677 struct wpa_supplicant *wpa_s;
678 char *path;
679 DBusMessage *reply = NULL;
680
681 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
5228401c 682 DBUS_TYPE_INVALID);
8fc2fb56
WS
683
684 wpa_s = get_iface_by_dbus_path(global, path);
5228401c 685 if (wpa_s == NULL)
8fc2fb56 686 reply = wpas_dbus_error_iface_unknown(message);
df509539 687 else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
5228401c 688 reply = wpas_dbus_error_unknown_error(
38279bdb
JM
689 message,
690 "wpa_supplicant couldn't remove this interface.");
8fc2fb56
WS
691 }
692
693 return reply;
694}
695
696
697/**
698 * wpas_dbus_handler_get_interface - Get the object path for an interface name
699 * @message: Pointer to incoming dbus message
700 * @global: %wpa_supplicant global data structure
701 * Returns: The object path of the interface object,
702 * or a dbus error message with more information
703 *
704 * Handler function for "getInterface" method call.
705 */
706DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
5228401c 707 struct wpa_global *global)
8fc2fb56
WS
708{
709 DBusMessage *reply = NULL;
710 const char *ifname;
711 const char *path;
712 struct wpa_supplicant *wpa_s;
713
714 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
5228401c 715 DBUS_TYPE_INVALID);
8fc2fb56
WS
716
717 wpa_s = wpa_supplicant_get_iface(global, ifname);
8a78e227 718 if (wpa_s == NULL || wpa_s->dbus_new_path == NULL)
5228401c 719 return wpas_dbus_error_iface_unknown(message);
8fc2fb56 720
c49cf2d6 721 path = wpa_s->dbus_new_path;
8fc2fb56 722 reply = dbus_message_new_method_return(message);
c2b8c674 723 if (reply == NULL)
a0caebf3 724 return wpas_dbus_error_no_memory(message);
8fc2fb56 725 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
5228401c 726 DBUS_TYPE_INVALID)) {
8fc2fb56 727 dbus_message_unref(reply);
a0caebf3 728 return wpas_dbus_error_no_memory(message);
8fc2fb56
WS
729 }
730
8fc2fb56
WS
731 return reply;
732}
733
734
735/**
db9133ac 736 * wpas_dbus_getter_debug_level - Get debug level
6aeeb6fa
DW
737 * @iter: Pointer to incoming dbus message iter
738 * @error: Location to store error on failure
739 * @user_data: Function specific data
740 * Returns: TRUE on success, FALSE on failure
8fc2fb56 741 *
db9133ac 742 * Getter for "DebugLevel" property.
8fc2fb56 743 */
1aa0fb77
DW
744dbus_bool_t wpas_dbus_getter_debug_level(
745 const struct wpa_dbus_property_desc *property_desc,
746 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 747{
a2753c28
MH
748 const char *str;
749 int idx = wpa_debug_level;
6aeeb6fa 750
a2753c28
MH
751 if (idx < 0)
752 idx = 0;
14dc0011
PS
753 if (idx > 5)
754 idx = 5;
a2753c28 755 str = debug_strings[idx];
6aeeb6fa
DW
756 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
757 &str, error);
db9133ac 758}
8fc2fb56 759
8fc2fb56 760
db9133ac
WS
761/**
762 * wpas_dbus_getter_debug_timestamp - Get debug timestamp
6aeeb6fa
DW
763 * @iter: Pointer to incoming dbus message iter
764 * @error: Location to store error on failure
765 * @user_data: Function specific data
766 * Returns: TRUE on success, FALSE on failure
db9133ac
WS
767 *
768 * Getter for "DebugTimestamp" property.
769 */
1aa0fb77
DW
770dbus_bool_t wpas_dbus_getter_debug_timestamp(
771 const struct wpa_dbus_property_desc *property_desc,
772 DBusMessageIter *iter, DBusError *error, void *user_data)
db9133ac 773{
6aeeb6fa
DW
774 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
775 &wpa_debug_timestamp, error);
8fc2fb56 776
db9133ac 777}
8fc2fb56 778
8fc2fb56 779
db9133ac
WS
780/**
781 * wpas_dbus_getter_debug_show_keys - Get debug show keys
6aeeb6fa
DW
782 * @iter: Pointer to incoming dbus message iter
783 * @error: Location to store error on failure
784 * @user_data: Function specific data
785 * Returns: TRUE on success, FALSE on failure
db9133ac
WS
786 *
787 * Getter for "DebugShowKeys" property.
788 */
1aa0fb77
DW
789dbus_bool_t wpas_dbus_getter_debug_show_keys(
790 const struct wpa_dbus_property_desc *property_desc,
791 DBusMessageIter *iter, DBusError *error, void *user_data)
db9133ac 792{
6aeeb6fa
DW
793 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
794 &wpa_debug_show_keys, error);
8fc2fb56 795
db9133ac 796}
8fc2fb56 797
db9133ac
WS
798/**
799 * wpas_dbus_setter_debug_level - Set debug level
6aeeb6fa
DW
800 * @iter: Pointer to incoming dbus message iter
801 * @error: Location to store error on failure
802 * @user_data: Function specific data
803 * Returns: TRUE on success, FALSE on failure
db9133ac
WS
804 *
805 * Setter for "DebugLevel" property.
806 */
1aa0fb77
DW
807dbus_bool_t wpas_dbus_setter_debug_level(
808 const struct wpa_dbus_property_desc *property_desc,
809 DBusMessageIter *iter, DBusError *error, void *user_data)
db9133ac 810{
6aeeb6fa 811 struct wpa_global *global = user_data;
a2753c28
MH
812 const char *str = NULL;
813 int i, val = -1;
8fc2fb56 814
6aeeb6fa
DW
815 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
816 &str))
817 return FALSE;
db9133ac 818
a2753c28
MH
819 for (i = 0; debug_strings[i]; i++)
820 if (os_strcmp(debug_strings[i], str) == 0) {
821 val = i;
822 break;
823 }
824
825 if (val < 0 ||
826 wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
db9133ac 827 wpa_debug_show_keys)) {
38279bdb
JM
828 dbus_set_error_const(error, DBUS_ERROR_FAILED,
829 "wrong debug level value");
6aeeb6fa 830 return FALSE;
8fc2fb56
WS
831 }
832
6aeeb6fa 833 return TRUE;
8fc2fb56
WS
834}
835
836
837/**
db9133ac 838 * wpas_dbus_setter_debug_timestamp - Set debug timestamp
6aeeb6fa
DW
839 * @iter: Pointer to incoming dbus message iter
840 * @error: Location to store error on failure
841 * @user_data: Function specific data
842 * Returns: TRUE on success, FALSE on failure
8fc2fb56 843 *
db9133ac 844 * Setter for "DebugTimestamp" property.
8fc2fb56 845 */
1aa0fb77
DW
846dbus_bool_t wpas_dbus_setter_debug_timestamp(
847 const struct wpa_dbus_property_desc *property_desc,
848 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 849{
6aeeb6fa 850 struct wpa_global *global = user_data;
db9133ac 851 dbus_bool_t val;
8fc2fb56 852
6aeeb6fa
DW
853 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
854 &val))
855 return FALSE;
8fc2fb56 856
db9133ac
WS
857 wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
858 wpa_debug_show_keys);
6aeeb6fa 859 return TRUE;
db9133ac 860}
8fc2fb56 861
8fc2fb56 862
db9133ac
WS
863/**
864 * wpas_dbus_setter_debug_show_keys - Set debug show keys
6aeeb6fa
DW
865 * @iter: Pointer to incoming dbus message iter
866 * @error: Location to store error on failure
867 * @user_data: Function specific data
868 * Returns: TRUE on success, FALSE on failure
db9133ac
WS
869 *
870 * Setter for "DebugShowKeys" property.
871 */
1aa0fb77
DW
872dbus_bool_t wpas_dbus_setter_debug_show_keys(
873 const struct wpa_dbus_property_desc *property_desc,
874 DBusMessageIter *iter, DBusError *error, void *user_data)
db9133ac 875{
6aeeb6fa 876 struct wpa_global *global = user_data;
db9133ac 877 dbus_bool_t val;
8fc2fb56 878
6aeeb6fa
DW
879 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
880 &val))
881 return FALSE;
8fc2fb56 882
db9133ac
WS
883 wpa_supplicant_set_debug_params(global, wpa_debug_level,
884 wpa_debug_timestamp,
885 val ? 1 : 0);
6aeeb6fa 886 return TRUE;
8fc2fb56
WS
887}
888
889
890/**
891 * wpas_dbus_getter_interfaces - Request registered interfaces list
6aeeb6fa
DW
892 * @iter: Pointer to incoming dbus message iter
893 * @error: Location to store error on failure
894 * @user_data: Function specific data
895 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
896 *
897 * Getter for "Interfaces" property. Handles requests
898 * by dbus clients to return list of registered interfaces objects
899 * paths
900 */
1aa0fb77
DW
901dbus_bool_t wpas_dbus_getter_interfaces(
902 const struct wpa_dbus_property_desc *property_desc,
903 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 904{
6aeeb6fa 905 struct wpa_global *global = user_data;
8fc2fb56 906 struct wpa_supplicant *wpa_s;
fcea0b7d
WS
907 const char **paths;
908 unsigned int i = 0, num = 0;
6aeeb6fa 909 dbus_bool_t success;
8fc2fb56 910
8a78e227
JM
911 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
912 if (wpa_s->dbus_new_path)
913 num++;
914 }
8fc2fb56 915
f9884c09 916 paths = os_calloc(num, sizeof(char *));
fcea0b7d 917 if (!paths) {
6aeeb6fa
DW
918 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
919 return FALSE;
8fc2fb56
WS
920 }
921
8a78e227
JM
922 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
923 if (wpa_s->dbus_new_path)
924 paths[i++] = wpa_s->dbus_new_path;
925 }
8fc2fb56 926
6aeeb6fa
DW
927 success = wpas_dbus_simple_array_property_getter(iter,
928 DBUS_TYPE_OBJECT_PATH,
929 paths, num, error);
8fc2fb56 930
fcea0b7d 931 os_free(paths);
6aeeb6fa 932 return success;
8fc2fb56
WS
933}
934
935
936/**
937 * wpas_dbus_getter_eap_methods - Request supported EAP methods list
6aeeb6fa
DW
938 * @iter: Pointer to incoming dbus message iter
939 * @error: Location to store error on failure
940 * @user_data: Function specific data
941 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
942 *
943 * Getter for "EapMethods" property. Handles requests
944 * by dbus clients to return list of strings with supported EAP methods
945 */
1aa0fb77
DW
946dbus_bool_t wpas_dbus_getter_eap_methods(
947 const struct wpa_dbus_property_desc *property_desc,
948 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 949{
8fc2fb56 950 char **eap_methods;
fcea0b7d 951 size_t num_items = 0;
6aeeb6fa 952 dbus_bool_t success;
8fc2fb56
WS
953
954 eap_methods = eap_get_names_as_string_array(&num_items);
fcea0b7d 955 if (!eap_methods) {
6aeeb6fa
DW
956 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
957 return FALSE;
8fc2fb56
WS
958 }
959
6aeeb6fa
DW
960 success = wpas_dbus_simple_array_property_getter(iter,
961 DBUS_TYPE_STRING,
962 eap_methods,
963 num_items, error);
8fc2fb56 964
fcea0b7d
WS
965 while (num_items)
966 os_free(eap_methods[--num_items]);
967 os_free(eap_methods);
6aeeb6fa 968 return success;
8fc2fb56
WS
969}
970
971
1634ac06
DW
972/**
973 * wpas_dbus_getter_global_capabilities - Request supported global capabilities
974 * @iter: Pointer to incoming dbus message iter
975 * @error: Location to store error on failure
976 * @user_data: Function specific data
977 * Returns: TRUE on success, FALSE on failure
978 *
979 * Getter for "Capabilities" property. Handles requests by dbus clients to
980 * return a list of strings with supported capabilities like AP, RSN IBSS,
981 * and P2P that are determined at compile time.
982 */
1aa0fb77
DW
983dbus_bool_t wpas_dbus_getter_global_capabilities(
984 const struct wpa_dbus_property_desc *property_desc,
985 DBusMessageIter *iter, DBusError *error, void *user_data)
1634ac06 986{
d7591aab
LR
987 const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
988 NULL, NULL, NULL, NULL };
1634ac06 989 size_t num_items = 0;
e4802127
MH
990#ifdef CONFIG_FILS
991 struct wpa_global *global = user_data;
992 struct wpa_supplicant *wpa_s;
993 int fils_supported = 0, fils_sk_pfs_supported = 0;
994
995 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
996 if (wpa_is_fils_supported(wpa_s))
997 fils_supported = 1;
998 if (wpa_is_fils_sk_pfs_supported(wpa_s))
999 fils_sk_pfs_supported = 1;
1000 }
1001#endif /* CONFIG_FILS */
1634ac06
DW
1002
1003#ifdef CONFIG_AP
1004 capabilities[num_items++] = "ap";
1005#endif /* CONFIG_AP */
1006#ifdef CONFIG_IBSS_RSN
1007 capabilities[num_items++] = "ibss-rsn";
1008#endif /* CONFIG_IBSS_RSN */
1009#ifdef CONFIG_P2P
1010 capabilities[num_items++] = "p2p";
1011#endif /* CONFIG_P2P */
1012#ifdef CONFIG_INTERWORKING
1013 capabilities[num_items++] = "interworking";
1014#endif /* CONFIG_INTERWORKING */
3cdb4ac0 1015 capabilities[num_items++] = "pmf";
e360010c
SB
1016#ifdef CONFIG_MESH
1017 capabilities[num_items++] = "mesh";
1018#endif /* CONFIG_MESH */
e4802127
MH
1019#ifdef CONFIG_FILS
1020 if (fils_supported)
1021 capabilities[num_items++] = "fils";
1022 if (fils_sk_pfs_supported)
1023 capabilities[num_items++] = "fils_sk_pfs";
1024#endif /* CONFIG_FILS */
eb7e7479
LR
1025#ifdef CONFIG_IEEE80211R
1026 capabilities[num_items++] = "ft";
1027#endif /* CONFIG_IEEE80211R */
d7591aab
LR
1028#ifdef CONFIG_SHA384
1029 capabilities[num_items++] = "sha384";
1030#endif /* CONFIG_SHA384 */
1634ac06
DW
1031
1032 return wpas_dbus_simple_array_property_getter(iter,
1033 DBUS_TYPE_STRING,
1034 capabilities,
1035 num_items, error);
1036}
1037
1038
d401b48f
JM
1039static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
1040 char **type, DBusMessage **reply)
8fc2fb56 1041{
d401b48f 1042 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
38279bdb
JM
1043 wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
1044 __func__);
db9a76c0 1045 *reply = wpas_dbus_error_invalid_args(
d401b48f
JM
1046 message, "Wrong Type value type. String required");
1047 return -1;
1048 }
1049 dbus_message_iter_get_basic(var, type);
1050 return 0;
1051}
8fc2fb56 1052
8fc2fb56 1053
d401b48f
JM
1054static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
1055 struct wpa_driver_scan_params *params,
1056 DBusMessage **reply)
1057{
1058 struct wpa_driver_scan_ssid *ssids = params->ssids;
1059 size_t ssids_num = 0;
1060 u8 *ssid;
1061 DBusMessageIter array_iter, sub_array_iter;
1062 char *val;
1063 int len;
8fc2fb56 1064
d401b48f 1065 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
38279bdb
JM
1066 wpa_printf(MSG_DEBUG,
1067 "%s[dbus]: ssids must be an array of arrays of bytes",
1068 __func__);
db9a76c0 1069 *reply = wpas_dbus_error_invalid_args(
38279bdb
JM
1070 message,
1071 "Wrong SSIDs value type. Array of arrays of bytes required");
d401b48f
JM
1072 return -1;
1073 }
8fc2fb56 1074
d401b48f 1075 dbus_message_iter_recurse(var, &array_iter);
8fc2fb56 1076
d401b48f 1077 if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
38279bdb
JM
1078 dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1079 wpa_printf(MSG_DEBUG,
1080 "%s[dbus]: ssids must be an array of arrays of bytes",
1081 __func__);
db9a76c0 1082 *reply = wpas_dbus_error_invalid_args(
38279bdb
JM
1083 message,
1084 "Wrong SSIDs value type. Array of arrays of bytes required");
d401b48f
JM
1085 return -1;
1086 }
8fc2fb56 1087
38279bdb 1088 while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
d401b48f 1089 if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
38279bdb
JM
1090 wpa_printf(MSG_DEBUG,
1091 "%s[dbus]: Too many ssids specified on scan dbus call",
1092 __func__);
db9a76c0 1093 *reply = wpas_dbus_error_invalid_args(
38279bdb
JM
1094 message,
1095 "Too many ssids specified. Specify at most four");
d401b48f
JM
1096 return -1;
1097 }
8fc2fb56 1098
d401b48f 1099 dbus_message_iter_recurse(&array_iter, &sub_array_iter);
8fc2fb56 1100
d401b48f 1101 dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
8fc2fb56 1102
eaa8eefe 1103 if (len > SSID_MAX_LEN) {
f9121813 1104 wpa_printf(MSG_DEBUG,
38279bdb 1105 "%s[dbus]: SSID too long (len=%d max_len=%d)",
eaa8eefe 1106 __func__, len, SSID_MAX_LEN);
f9121813
SL
1107 *reply = wpas_dbus_error_invalid_args(
1108 message, "Invalid SSID: too long");
1109 return -1;
1110 }
1111
556522ee 1112 if (len != 0) {
a1f11e34 1113 ssid = os_memdup(val, len);
556522ee 1114 if (ssid == NULL) {
a0caebf3 1115 *reply = wpas_dbus_error_no_memory(message);
556522ee
DK
1116 return -1;
1117 }
556522ee
DK
1118 } else {
1119 /* Allow zero-length SSIDs */
1120 ssid = NULL;
d401b48f 1121 }
556522ee 1122
d401b48f
JM
1123 ssids[ssids_num].ssid = ssid;
1124 ssids[ssids_num].ssid_len = len;
5228401c 1125
d401b48f
JM
1126 dbus_message_iter_next(&array_iter);
1127 ssids_num++;
1128 }
8fc2fb56 1129
d401b48f
JM
1130 params->num_ssids = ssids_num;
1131 return 0;
1132}
8fc2fb56 1133
8fc2fb56 1134
d401b48f
JM
1135static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
1136 struct wpa_driver_scan_params *params,
1137 DBusMessage **reply)
1138{
1139 u8 *ies = NULL, *nies;
1140 int ies_len = 0;
1141 DBusMessageIter array_iter, sub_array_iter;
1142 char *val;
1143 int len;
8fc2fb56 1144
d401b48f 1145 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
38279bdb
JM
1146 wpa_printf(MSG_DEBUG,
1147 "%s[dbus]: ies must be an array of arrays of bytes",
1148 __func__);
db9a76c0 1149 *reply = wpas_dbus_error_invalid_args(
38279bdb
JM
1150 message,
1151 "Wrong IEs value type. Array of arrays of bytes required");
d401b48f
JM
1152 return -1;
1153 }
8fc2fb56 1154
d401b48f 1155 dbus_message_iter_recurse(var, &array_iter);
8fc2fb56 1156
d401b48f 1157 if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
38279bdb
JM
1158 dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1159 wpa_printf(MSG_DEBUG,
1160 "%s[dbus]: ies must be an array of arrays of bytes",
1161 __func__);
db9a76c0 1162 *reply = wpas_dbus_error_invalid_args(
d401b48f
JM
1163 message, "Wrong IEs value type. Array required");
1164 return -1;
1165 }
8fc2fb56 1166
38279bdb 1167 while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
d401b48f 1168 dbus_message_iter_recurse(&array_iter, &sub_array_iter);
8fc2fb56 1169
d401b48f
JM
1170 dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1171 if (len == 0) {
1172 dbus_message_iter_next(&array_iter);
1173 continue;
1174 }
8fc2fb56 1175
d401b48f
JM
1176 nies = os_realloc(ies, ies_len + len);
1177 if (nies == NULL) {
d401b48f 1178 os_free(ies);
a0caebf3 1179 *reply = wpas_dbus_error_no_memory(message);
d401b48f
JM
1180 return -1;
1181 }
1182 ies = nies;
1183 os_memcpy(ies + ies_len, val, len);
1184 ies_len += len;
8fc2fb56 1185
d401b48f
JM
1186 dbus_message_iter_next(&array_iter);
1187 }
5228401c 1188
d401b48f
JM
1189 params->extra_ies = ies;
1190 params->extra_ies_len = ies_len;
1191 return 0;
1192}
8fc2fb56 1193
8fc2fb56 1194
d401b48f
JM
1195static int wpas_dbus_get_scan_channels(DBusMessage *message,
1196 DBusMessageIter *var,
1197 struct wpa_driver_scan_params *params,
1198 DBusMessage **reply)
1199{
1200 DBusMessageIter array_iter, sub_array_iter;
1201 int *freqs = NULL, *nfreqs;
1202 int freqs_num = 0;
8fc2fb56 1203
d401b48f 1204 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
38279bdb
JM
1205 wpa_printf(MSG_DEBUG,
1206 "%s[dbus]: Channels must be an array of structs",
1207 __func__);
db9a76c0 1208 *reply = wpas_dbus_error_invalid_args(
38279bdb
JM
1209 message,
1210 "Wrong Channels value type. Array of structs required");
d401b48f
JM
1211 return -1;
1212 }
8fc2fb56 1213
d401b48f 1214 dbus_message_iter_recurse(var, &array_iter);
8fc2fb56 1215
d401b48f
JM
1216 if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
1217 wpa_printf(MSG_DEBUG,
38279bdb
JM
1218 "%s[dbus]: Channels must be an array of structs",
1219 __func__);
db9a76c0 1220 *reply = wpas_dbus_error_invalid_args(
38279bdb
JM
1221 message,
1222 "Wrong Channels value type. Array of structs required");
d401b48f
JM
1223 return -1;
1224 }
8fc2fb56 1225
d401b48f
JM
1226 while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
1227 {
1228 int freq, width;
8fc2fb56 1229
d401b48f 1230 dbus_message_iter_recurse(&array_iter, &sub_array_iter);
8fc2fb56 1231
d401b48f
JM
1232 if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
1233 DBUS_TYPE_UINT32) {
38279bdb
JM
1234 wpa_printf(MSG_DEBUG,
1235 "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
1236 __func__,
d401b48f
JM
1237 dbus_message_iter_get_arg_type(
1238 &sub_array_iter));
db9a76c0 1239 *reply = wpas_dbus_error_invalid_args(
38279bdb
JM
1240 message,
1241 "Wrong Channel struct. Two UINT32s required");
d401b48f
JM
1242 os_free(freqs);
1243 return -1;
1244 }
1245 dbus_message_iter_get_basic(&sub_array_iter, &freq);
8fc2fb56 1246
d401b48f
JM
1247 if (!dbus_message_iter_next(&sub_array_iter) ||
1248 dbus_message_iter_get_arg_type(&sub_array_iter) !=
1249 DBUS_TYPE_UINT32) {
38279bdb
JM
1250 wpa_printf(MSG_DEBUG,
1251 "%s[dbus]: Channel must by specified by struct of two UINT32s",
1252 __func__);
db9a76c0 1253 *reply = wpas_dbus_error_invalid_args(
d401b48f
JM
1254 message,
1255 "Wrong Channel struct. Two UINT32s required");
1256 os_free(freqs);
1257 return -1;
1258 }
8fc2fb56 1259
d401b48f 1260 dbus_message_iter_get_basic(&sub_array_iter, &width);
8fc2fb56 1261
5228401c 1262#define FREQS_ALLOC_CHUNK 32
d401b48f 1263 if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
067ffa26
JM
1264 nfreqs = os_realloc_array(
1265 freqs, freqs_num + FREQS_ALLOC_CHUNK,
1266 sizeof(int));
d401b48f
JM
1267 if (nfreqs == NULL)
1268 os_free(freqs);
1269 freqs = nfreqs;
1270 }
1271 if (freqs == NULL) {
a0caebf3 1272 *reply = wpas_dbus_error_no_memory(message);
d401b48f
JM
1273 return -1;
1274 }
8fc2fb56 1275
d401b48f 1276 freqs[freqs_num] = freq;
8fc2fb56 1277
d401b48f
JM
1278 freqs_num++;
1279 dbus_message_iter_next(&array_iter);
1280 }
8fc2fb56 1281
067ffa26 1282 nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
d401b48f
JM
1283 if (nfreqs == NULL)
1284 os_free(freqs);
1285 freqs = nfreqs;
1286 if (freqs == NULL) {
a0caebf3 1287 *reply = wpas_dbus_error_no_memory(message);
d401b48f
JM
1288 return -1;
1289 }
1290 freqs[freqs_num] = 0;
1291
1292 params->freqs = freqs;
1293 return 0;
1294}
8fc2fb56 1295
d401b48f 1296
538922a6
DW
1297static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
1298 DBusMessageIter *var,
1299 dbus_bool_t *allow,
1300 DBusMessage **reply)
1301{
1302 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
38279bdb
JM
1303 wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
1304 __func__);
538922a6
DW
1305 *reply = wpas_dbus_error_invalid_args(
1306 message, "Wrong Type value type. Boolean required");
1307 return -1;
1308 }
1309 dbus_message_iter_get_basic(var, allow);
1310 return 0;
1311}
1312
1313
d401b48f
JM
1314/**
1315 * wpas_dbus_handler_scan - Request a wireless scan on an interface
1316 * @message: Pointer to incoming dbus message
1317 * @wpa_s: wpa_supplicant structure for a network interface
1318 * Returns: NULL indicating success or DBus error message on failure
1319 *
1320 * Handler function for "Scan" method call of a network device. Requests
1321 * that wpa_supplicant perform a wireless scan as soon as possible
1322 * on a particular wireless interface.
1323 */
1324DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
1325 struct wpa_supplicant *wpa_s)
1326{
1327 DBusMessage *reply = NULL;
1328 DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
1329 char *key = NULL, *type = NULL;
1330 struct wpa_driver_scan_params params;
1331 size_t i;
538922a6 1332 dbus_bool_t allow_roam = 1;
d401b48f
JM
1333
1334 os_memset(&params, 0, sizeof(params));
1335
1336 dbus_message_iter_init(message, &iter);
1337
1338 dbus_message_iter_recurse(&iter, &dict_iter);
1339
1340 while (dbus_message_iter_get_arg_type(&dict_iter) ==
38279bdb 1341 DBUS_TYPE_DICT_ENTRY) {
d401b48f
JM
1342 dbus_message_iter_recurse(&dict_iter, &entry_iter);
1343 dbus_message_iter_get_basic(&entry_iter, &key);
1344 dbus_message_iter_next(&entry_iter);
1345 dbus_message_iter_recurse(&entry_iter, &variant_iter);
1346
1347 if (os_strcmp(key, "Type") == 0) {
1348 if (wpas_dbus_get_scan_type(message, &variant_iter,
1349 &type, &reply) < 0)
1350 goto out;
1351 } else if (os_strcmp(key, "SSIDs") == 0) {
1352 if (wpas_dbus_get_scan_ssids(message, &variant_iter,
1353 &params, &reply) < 0)
1354 goto out;
1355 } else if (os_strcmp(key, "IEs") == 0) {
1356 if (wpas_dbus_get_scan_ies(message, &variant_iter,
1357 &params, &reply) < 0)
1358 goto out;
1359 } else if (os_strcmp(key, "Channels") == 0) {
1360 if (wpas_dbus_get_scan_channels(message, &variant_iter,
1361 &params, &reply) < 0)
1362 goto out;
538922a6
DW
1363 } else if (os_strcmp(key, "AllowRoam") == 0) {
1364 if (wpas_dbus_get_scan_allow_roam(message,
1365 &variant_iter,
1366 &allow_roam,
1367 &reply) < 0)
1368 goto out;
5228401c 1369 } else {
38279bdb
JM
1370 wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
1371 __func__, key);
db9a76c0 1372 reply = wpas_dbus_error_invalid_args(message, key);
8fc2fb56
WS
1373 goto out;
1374 }
1375
1376 dbus_message_iter_next(&dict_iter);
1377 }
1378
1379 if (!type) {
38279bdb
JM
1380 wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
1381 __func__);
db9a76c0 1382 reply = wpas_dbus_error_invalid_args(message, key);
8fc2fb56
WS
1383 goto out;
1384 }
1385
38279bdb 1386 if (os_strcmp(type, "passive") == 0) {
d401b48f 1387 if (params.num_ssids || params.extra_ies_len) {
38279bdb
JM
1388 wpa_printf(MSG_DEBUG,
1389 "%s[dbus]: SSIDs or IEs specified for passive scan.",
1390 __func__);
db9a76c0 1391 reply = wpas_dbus_error_invalid_args(
38279bdb
JM
1392 message,
1393 "You can specify only Channels in passive scan");
8fc2fb56 1394 goto out;
5228401c 1395 } else {
a5da6574
AS
1396 if (wpa_s->sched_scanning) {
1397 wpa_printf(MSG_DEBUG,
1398 "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1399 __func__);
1400 wpa_supplicant_cancel_sched_scan(wpa_s);
1401 }
1402
1403 if (params.freqs && params.freqs[0]) {
1fbff0b5 1404 wpa_s->last_scan_req = MANUAL_SCAN_REQ;
a5da6574
AS
1405 if (wpa_supplicant_trigger_scan(wpa_s,
1406 &params)) {
1407 reply = wpas_dbus_error_scan_error(
1408 message,
1409 "Scan request rejected");
1410 }
1411 } else {
1412 wpa_s->scan_req = MANUAL_SCAN_REQ;
1413 wpa_supplicant_req_scan(wpa_s, 0, 0);
1414 }
8fc2fb56 1415 }
38279bdb 1416 } else if (os_strcmp(type, "active") == 0) {
a7af023b
DK
1417 if (!params.num_ssids) {
1418 /* Add wildcard ssid */
1419 params.num_ssids++;
1420 }
7c865c68
TB
1421#ifdef CONFIG_AUTOSCAN
1422 autoscan_deinit(wpa_s);
1423#endif /* CONFIG_AUTOSCAN */
a5da6574
AS
1424 if (wpa_s->sched_scanning) {
1425 wpa_printf(MSG_DEBUG,
1426 "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1427 __func__);
1428 wpa_supplicant_cancel_sched_scan(wpa_s);
1429 }
1430
1fbff0b5 1431 wpa_s->last_scan_req = MANUAL_SCAN_REQ;
e9b32dae 1432 if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1433 reply = wpas_dbus_error_scan_error(
1434 message, "Scan request rejected");
1435 }
5228401c 1436 } else {
38279bdb
JM
1437 wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
1438 __func__, type);
db9a76c0
JM
1439 reply = wpas_dbus_error_invalid_args(message,
1440 "Wrong scan type");
8fc2fb56
WS
1441 goto out;
1442 }
1443
538922a6
DW
1444 if (!allow_roam)
1445 wpa_s->scan_res_handler = scan_only_handler;
1446
8fc2fb56 1447out:
d401b48f
JM
1448 for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
1449 os_free((u8 *) params.ssids[i].ssid);
5228401c 1450 os_free((u8 *) params.extra_ies);
8fc2fb56
WS
1451 os_free(params.freqs);
1452 return reply;
1453}
1454
1455
19395054
SB
1456/*
1457 * wpas_dbus_handler_abort_scan - Request an ongoing scan to be aborted
1458 * @message: Pointer to incoming dbus message
1459 * @wpa_s: wpa_supplicant structure for a network interface
1460 * Returns: Abort failed or no scan in progress DBus error message on failure
1461 * or NULL otherwise.
1462 *
1463 * Handler function for "AbortScan" method call of network interface.
1464 */
1465DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message,
1466 struct wpa_supplicant *wpa_s)
1467{
1468 if (wpas_abort_ongoing_scan(wpa_s) < 0)
1469 return dbus_message_new_error(
1470 message, WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
1471 "Abort failed or no scan in progress");
1472
1473 return NULL;
1474}
1475
1476
7a4a93b9
DW
1477/**
1478 * wpas_dbus_handler_signal_poll - Request immediate signal properties
1479 * @message: Pointer to incoming dbus message
1480 * @wpa_s: wpa_supplicant structure for a network interface
1481 * Returns: NULL indicating success or DBus error message on failure
1482 *
1483 * Handler function for "SignalPoll" method call of a network device. Requests
1484 * that wpa_supplicant read signal properties like RSSI, noise, and link
1485 * speed and return them.
1486 */
1487DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
1488 struct wpa_supplicant *wpa_s)
1489{
1490 struct wpa_signal_info si;
1491 DBusMessage *reply = NULL;
1492 DBusMessageIter iter, iter_dict, variant_iter;
1493 int ret;
1494
1495 ret = wpa_drv_signal_poll(wpa_s, &si);
1496 if (ret) {
1497 return dbus_message_new_error(message, DBUS_ERROR_FAILED,
1498 "Failed to read signal");
1499 }
1500
1501 reply = dbus_message_new_method_return(message);
1502 if (reply == NULL)
1503 goto nomem;
1504
1505 dbus_message_iter_init_append(reply, &iter);
1506
1507 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
e3c4f0b5
JM
1508 "a{sv}", &variant_iter) ||
1509 !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
1510 !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
1511 si.current_signal) ||
1512 !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
1513 si.current_txrate / 1000) ||
1514 !wpa_dbus_dict_append_int32(&iter_dict, "noise",
1515 si.current_noise) ||
1516 !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
1517 si.frequency) ||
1518 (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
1519 !wpa_dbus_dict_append_string(
1520 &iter_dict, "width",
1521 channel_width_to_string(si.chanwidth))) ||
1522 (si.center_frq1 > 0 && si.center_frq2 > 0 &&
1523 (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
1524 si.center_frq1) ||
1525 !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
1526 si.center_frq2))) ||
1527 (si.avg_signal &&
1528 !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
1529 si.avg_signal)) ||
1530 !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
1531 !dbus_message_iter_close_container(&iter, &variant_iter))
7a4a93b9
DW
1532 goto nomem;
1533
1534 return reply;
1535
1536nomem:
1537 if (reply)
1538 dbus_message_unref(reply);
a0caebf3 1539 return wpas_dbus_error_no_memory(message);
7a4a93b9
DW
1540}
1541
1542
8fc2fb56
WS
1543/*
1544 * wpas_dbus_handler_disconnect - Terminate the current connection
1545 * @message: Pointer to incoming dbus message
1546 * @wpa_s: wpa_supplicant structure for a network interface
1547 * Returns: NotConnected DBus error message if already not connected
1548 * or NULL otherwise.
1549 *
1550 * Handler function for "Disconnect" method call of network interface.
1551 */
1552DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
5228401c 1553 struct wpa_supplicant *wpa_s)
8fc2fb56
WS
1554{
1555 if (wpa_s->current_ssid != NULL) {
5f040be4 1556 wpas_request_disconnection(wpa_s);
8fc2fb56
WS
1557 return NULL;
1558 }
5228401c
JM
1559
1560 return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1561 "This interface is not connected");
8fc2fb56
WS
1562}
1563
1564
1565/**
1566 * wpas_dbus_new_iface_add_network - Add a new configured network
1567 * @message: Pointer to incoming dbus message
1568 * @wpa_s: wpa_supplicant structure for a network interface
1569 * Returns: A dbus message containing the object path of the new network
1570 *
1571 * Handler function for "AddNetwork" method call of a network interface.
1572 */
1573DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
5228401c 1574 struct wpa_supplicant *wpa_s)
8fc2fb56
WS
1575{
1576 DBusMessage *reply = NULL;
1577 DBusMessageIter iter;
1578 struct wpa_ssid *ssid = NULL;
3e87bd54 1579 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
6aeeb6fa 1580 DBusError error;
8fc2fb56
WS
1581
1582 dbus_message_iter_init(message, &iter);
1583
8a78e227 1584 if (wpa_s->dbus_new_path)
d015bb05 1585 ssid = wpa_supplicant_add_network(wpa_s);
8fc2fb56 1586 if (ssid == NULL) {
38279bdb
JM
1587 wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
1588 __func__);
5228401c
JM
1589 reply = wpas_dbus_error_unknown_error(
1590 message,
38279bdb 1591 "wpa_supplicant could not add a network on this interface.");
8fc2fb56
WS
1592 goto err;
1593 }
8fc2fb56 1594
6aeeb6fa
DW
1595 dbus_error_init(&error);
1596 if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
38279bdb
JM
1597 wpa_printf(MSG_DEBUG,
1598 "%s[dbus]: control interface couldn't set network properties",
1599 __func__);
6aeeb6fa
DW
1600 reply = wpas_dbus_reply_new_from_error(message, &error,
1601 DBUS_ERROR_INVALID_ARGS,
1602 "Failed to add network");
1603 dbus_error_free(&error);
8fc2fb56
WS
1604 goto err;
1605 }
1606
1607 /* Construct the object path for this network. */
5228401c
JM
1608 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1609 "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
c49cf2d6 1610 wpa_s->dbus_new_path, ssid->id);
8fc2fb56
WS
1611
1612 reply = dbus_message_new_method_return(message);
1613 if (reply == NULL) {
a0caebf3 1614 reply = wpas_dbus_error_no_memory(message);
8fc2fb56
WS
1615 goto err;
1616 }
1617 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
5228401c 1618 DBUS_TYPE_INVALID)) {
8fc2fb56 1619 dbus_message_unref(reply);
a0caebf3 1620 reply = wpas_dbus_error_no_memory(message);
8fc2fb56
WS
1621 goto err;
1622 }
1623
8fc2fb56
WS
1624 return reply;
1625
1626err:
1627 if (ssid) {
1628 wpas_notify_network_removed(wpa_s, ssid);
1629 wpa_config_remove_network(wpa_s->conf, ssid->id);
1630 }
8fc2fb56
WS
1631 return reply;
1632}
1633
1634
6ed31175 1635/**
481e66b1 1636 * wpas_dbus_handler_reassociate - Reassociate
6ed31175
PS
1637 * @message: Pointer to incoming dbus message
1638 * @wpa_s: wpa_supplicant structure for a network interface
481e66b1 1639 * Returns: InterfaceDisabled DBus error message if disabled
6ed31175
PS
1640 * or NULL otherwise.
1641 *
1642 * Handler function for "Reassociate" method call of network interface.
1643 */
1644DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
1645 struct wpa_supplicant *wpa_s)
1646{
481e66b1 1647 if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
9796a86c 1648 wpas_request_connection(wpa_s);
6ed31175
PS
1649 return NULL;
1650 }
1651
481e66b1
FC
1652 return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
1653 "This interface is disabled");
6ed31175
PS
1654}
1655
1656
c143c3b7
NW
1657/**
1658 * wpas_dbus_handler_expect_disconnect - ExpectDisconnect
1659 * @message: Pointer to incoming dbus message
1660 * @global: %wpa_supplicant global data structure
1661 * Returns: NULL
1662 *
1663 * Handler function for notifying system there will be a expected disconnect.
1664 * This will prevent wpa_supplicant from adding blacklists upon next disconnect..
1665 */
1666DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
1667 struct wpa_global *global)
1668{
1669 struct wpa_supplicant *wpa_s = global->ifaces;
1670
1671 for (; wpa_s; wpa_s = wpa_s->next)
1672 if (wpa_s->wpa_state >= WPA_ASSOCIATED)
1673 wpa_s->own_disconnect_req = 1;
1674 return NULL;
1675}
1676
1677
0f44ec8e
PQ
1678/**
1679 * wpas_dbus_handler_reattach - Reattach to current AP
1680 * @message: Pointer to incoming dbus message
1681 * @wpa_s: wpa_supplicant structure for a network interface
1682 * Returns: NotConnected DBus error message if not connected
1683 * or NULL otherwise.
1684 *
1685 * Handler function for "Reattach" method call of network interface.
1686 */
1687DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
1688 struct wpa_supplicant *wpa_s)
1689{
1690 if (wpa_s->current_ssid != NULL) {
1691 wpa_s->reattach = 1;
1692 wpas_request_connection(wpa_s);
1693 return NULL;
1694 }
1695
1696 return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1697 "This interface is not connected");
1698}
1699
1700
b649c0af
MH
1701/**
1702 * wpas_dbus_handler_reconnect - Reconnect if disconnected
1703 * @message: Pointer to incoming dbus message
1704 * @wpa_s: wpa_supplicant structure for a network interface
1705 * Returns: InterfaceDisabled DBus error message if disabled
1706 * or NULL otherwise.
1707 *
1708 * Handler function for "Reconnect" method call of network interface.
1709 */
1710DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
1711 struct wpa_supplicant *wpa_s)
1712{
1713 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
1714 return dbus_message_new_error(message,
1715 WPAS_DBUS_ERROR_IFACE_DISABLED,
1716 "This interface is disabled");
1717 }
1718
1719 if (wpa_s->disconnected)
1720 wpas_request_connection(wpa_s);
1721 return NULL;
1722}
1723
1724
8fc2fb56
WS
1725/**
1726 * wpas_dbus_handler_remove_network - Remove a configured network
1727 * @message: Pointer to incoming dbus message
1728 * @wpa_s: wpa_supplicant structure for a network interface
1729 * Returns: NULL on success or dbus error on failure
1730 *
1731 * Handler function for "RemoveNetwork" method call of a network interface.
1732 */
1733DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
5228401c 1734 struct wpa_supplicant *wpa_s)
8fc2fb56
WS
1735{
1736 DBusMessage *reply = NULL;
1737 const char *op;
054dc313 1738 char *iface, *net_id;
8fc2fb56 1739 int id;
d015bb05 1740 int result;
8fc2fb56
WS
1741
1742 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
5228401c 1743 DBUS_TYPE_INVALID);
8fc2fb56
WS
1744
1745 /* Extract the network ID and ensure the network */
1746 /* is actually a child of this interface */
054dc313
JM
1747 iface = wpas_dbus_new_decompose_object_path(op,
1748 WPAS_DBUS_NEW_NETWORKS_PART,
1749 &net_id);
8a78e227 1750 if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
45ac5793 1751 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
db9a76c0 1752 reply = wpas_dbus_error_invalid_args(message, op);
8fc2fb56
WS
1753 goto out;
1754 }
1755
45ac5793 1756 errno = 0;
8fc2fb56 1757 id = strtoul(net_id, NULL, 10);
45ac5793 1758 if (errno != 0) {
db9a76c0 1759 reply = wpas_dbus_error_invalid_args(message, op);
8fc2fb56
WS
1760 goto out;
1761 }
1762
d015bb05
RP
1763 result = wpa_supplicant_remove_network(wpa_s, id);
1764 if (result == -1) {
8fc2fb56
WS
1765 reply = wpas_dbus_error_network_unknown(message);
1766 goto out;
1767 }
d015bb05 1768 if (result == -2) {
316f92cd 1769 wpa_printf(MSG_ERROR,
38279bdb
JM
1770 "%s[dbus]: error occurred when removing network %d",
1771 __func__, id);
316f92cd 1772 reply = wpas_dbus_error_unknown_error(
38279bdb
JM
1773 message,
1774 "error removing the specified network on is interface.");
316f92cd
HM
1775 goto out;
1776 }
8fc2fb56
WS
1777
1778out:
1779 os_free(iface);
8fc2fb56
WS
1780 return reply;
1781}
1782
1783
7c49fdd0
SL
1784static void remove_network(void *arg, struct wpa_ssid *ssid)
1785{
1786 struct wpa_supplicant *wpa_s = arg;
1787
1788 wpas_notify_network_removed(wpa_s, ssid);
1789
1790 if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1791 wpa_printf(MSG_ERROR,
38279bdb
JM
1792 "%s[dbus]: error occurred when removing network %d",
1793 __func__, ssid->id);
7c49fdd0
SL
1794 return;
1795 }
1796
1797 if (ssid == wpa_s->current_ssid)
07783eaa
JM
1798 wpa_supplicant_deauthenticate(wpa_s,
1799 WLAN_REASON_DEAUTH_LEAVING);
7c49fdd0
SL
1800}
1801
1802
1803/**
1804 * wpas_dbus_handler_remove_all_networks - Remove all configured networks
1805 * @message: Pointer to incoming dbus message
1806 * @wpa_s: wpa_supplicant structure for a network interface
1807 * Returns: NULL on success or dbus error on failure
1808 *
1809 * Handler function for "RemoveAllNetworks" method call of a network interface.
1810 */
1811DBusMessage * wpas_dbus_handler_remove_all_networks(
1812 DBusMessage *message, struct wpa_supplicant *wpa_s)
1813{
725fc39e
DS
1814 if (wpa_s->sched_scanning)
1815 wpa_supplicant_cancel_sched_scan(wpa_s);
1816
7c49fdd0
SL
1817 /* NB: could check for failure and return an error */
1818 wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
1819 return NULL;
1820}
1821
1822
8fc2fb56
WS
1823/**
1824 * wpas_dbus_handler_select_network - Attempt association with a network
1825 * @message: Pointer to incoming dbus message
1826 * @wpa_s: wpa_supplicant structure for a network interface
1827 * Returns: NULL on success or dbus error on failure
1828 *
1829 * Handler function for "SelectNetwork" method call of network interface.
1830 */
1831DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
5228401c 1832 struct wpa_supplicant *wpa_s)
8fc2fb56
WS
1833{
1834 DBusMessage *reply = NULL;
1835 const char *op;
054dc313 1836 char *iface, *net_id;
8fc2fb56
WS
1837 int id;
1838 struct wpa_ssid *ssid;
1839
1840 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
5228401c 1841 DBUS_TYPE_INVALID);
8fc2fb56
WS
1842
1843 /* Extract the network ID and ensure the network */
1844 /* is actually a child of this interface */
054dc313
JM
1845 iface = wpas_dbus_new_decompose_object_path(op,
1846 WPAS_DBUS_NEW_NETWORKS_PART,
1847 &net_id);
8a78e227 1848 if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
45ac5793 1849 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
db9a76c0 1850 reply = wpas_dbus_error_invalid_args(message, op);
8fc2fb56
WS
1851 goto out;
1852 }
1853
45ac5793 1854 errno = 0;
8fc2fb56 1855 id = strtoul(net_id, NULL, 10);
45ac5793 1856 if (errno != 0) {
db9a76c0 1857 reply = wpas_dbus_error_invalid_args(message, op);
8fc2fb56
WS
1858 goto out;
1859 }
1860
1861 ssid = wpa_config_get_network(wpa_s->conf, id);
1862 if (ssid == NULL) {
1863 reply = wpas_dbus_error_network_unknown(message);
1864 goto out;
1865 }
5228401c 1866
8fc2fb56
WS
1867 /* Finally, associate with the network */
1868 wpa_supplicant_select_network(wpa_s, ssid);
1869
1870out:
1871 os_free(iface);
8fc2fb56
WS
1872 return reply;
1873}
1874
1875
e9c3c1af
DW
1876/**
1877 * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
1878 * @message: Pointer to incoming dbus message
1879 * @wpa_s: wpa_supplicant structure for a network interface
1880 * Returns: NULL on success or dbus error on failure
1881 *
1882 * Handler function for "NetworkReply" method call of network interface.
1883 */
1884DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
1885 struct wpa_supplicant *wpa_s)
1886{
1887#ifdef IEEE8021X_EAPOL
1888 DBusMessage *reply = NULL;
1889 const char *op, *field, *value;
054dc313 1890 char *iface, *net_id;
e9c3c1af
DW
1891 int id;
1892 struct wpa_ssid *ssid;
1893
1894 if (!dbus_message_get_args(message, NULL,
38279bdb
JM
1895 DBUS_TYPE_OBJECT_PATH, &op,
1896 DBUS_TYPE_STRING, &field,
1897 DBUS_TYPE_STRING, &value,
1898 DBUS_TYPE_INVALID))
e9c3c1af
DW
1899 return wpas_dbus_error_invalid_args(message, NULL);
1900
1901 /* Extract the network ID and ensure the network */
1902 /* is actually a child of this interface */
054dc313
JM
1903 iface = wpas_dbus_new_decompose_object_path(op,
1904 WPAS_DBUS_NEW_NETWORKS_PART,
1905 &net_id);
8a78e227 1906 if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
45ac5793 1907 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
e9c3c1af
DW
1908 reply = wpas_dbus_error_invalid_args(message, op);
1909 goto out;
1910 }
1911
45ac5793 1912 errno = 0;
e9c3c1af 1913 id = strtoul(net_id, NULL, 10);
45ac5793 1914 if (errno != 0) {
e9c3c1af
DW
1915 reply = wpas_dbus_error_invalid_args(message, net_id);
1916 goto out;
1917 }
1918
1919 ssid = wpa_config_get_network(wpa_s->conf, id);
1920 if (ssid == NULL) {
1921 reply = wpas_dbus_error_network_unknown(message);
1922 goto out;
1923 }
1924
1925 if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
1926 field, value) < 0)
1927 reply = wpas_dbus_error_invalid_args(message, field);
1928 else {
1929 /* Tell EAP to retry immediately */
1930 eapol_sm_notify_ctrl_response(wpa_s->eapol);
1931 }
1932
1933out:
1934 os_free(iface);
e9c3c1af
DW
1935 return reply;
1936#else /* IEEE8021X_EAPOL */
fb7e7dae 1937 wpa_printf(MSG_DEBUG, "dbus: 802.1X not included");
e9c3c1af
DW
1938 return wpas_dbus_error_unknown_error(message, "802.1X not included");
1939#endif /* IEEE8021X_EAPOL */
1940}
1941
1942
21f01a8e
JM
1943#ifndef CONFIG_NO_CONFIG_BLOBS
1944
8fc2fb56
WS
1945/**
1946 * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
1947 * @message: Pointer to incoming dbus message
1948 * @wpa_s: %wpa_supplicant data structure
1949 * Returns: A dbus message containing an error on failure or NULL on success
1950 *
1951 * Asks wpa_supplicant to internally store a binary blobs.
1952 */
1953DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
5228401c 1954 struct wpa_supplicant *wpa_s)
8fc2fb56
WS
1955{
1956 DBusMessage *reply = NULL;
1957 DBusMessageIter iter, array_iter;
1958
1959 char *blob_name;
1960 u8 *blob_data;
1961 int blob_len;
1962 struct wpa_config_blob *blob = NULL;
1963
1964 dbus_message_iter_init(message, &iter);
1965 dbus_message_iter_get_basic(&iter, &blob_name);
1966
1967 if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
5228401c
JM
1968 return dbus_message_new_error(message,
1969 WPAS_DBUS_ERROR_BLOB_EXISTS,
1970 NULL);
8fc2fb56
WS
1971 }
1972
1973 dbus_message_iter_next(&iter);
1974 dbus_message_iter_recurse(&iter, &array_iter);
1975
1976 dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
1977
1978 blob = os_zalloc(sizeof(*blob));
1979 if (!blob) {
a0caebf3 1980 reply = wpas_dbus_error_no_memory(message);
8fc2fb56
WS
1981 goto err;
1982 }
1983
a1f11e34 1984 blob->data = os_memdup(blob_data, blob_len);
a0caebf3
JM
1985 blob->name = os_strdup(blob_name);
1986 if (!blob->data || !blob->name) {
1987 reply = wpas_dbus_error_no_memory(message);
8fc2fb56
WS
1988 goto err;
1989 }
8fc2fb56 1990 blob->len = blob_len;
8fc2fb56
WS
1991
1992 wpa_config_set_blob(wpa_s->conf, blob);
1993 wpas_notify_blob_added(wpa_s, blob->name);
1994
1995 return reply;
1996
1997err:
1998 if (blob) {
1999 os_free(blob->name);
2000 os_free(blob->data);
2001 os_free(blob);
2002 }
2003 return reply;
2004}
2005
2006
2007/**
2008 * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
2009 * @message: Pointer to incoming dbus message
2010 * @wpa_s: %wpa_supplicant data structure
2011 * Returns: A dbus message containing array of bytes (blob)
2012 *
2013 * Gets one wpa_supplicant's binary blobs.
2014 */
2015DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
5228401c 2016 struct wpa_supplicant *wpa_s)
8fc2fb56
WS
2017{
2018 DBusMessage *reply = NULL;
2019 DBusMessageIter iter, array_iter;
2020
2021 char *blob_name;
2022 const struct wpa_config_blob *blob;
2023
2024 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
5228401c 2025 DBUS_TYPE_INVALID);
8fc2fb56
WS
2026
2027 blob = wpa_config_get_blob(wpa_s->conf, blob_name);
2028 if (!blob) {
5228401c
JM
2029 return dbus_message_new_error(message,
2030 WPAS_DBUS_ERROR_BLOB_UNKNOWN,
2031 "Blob id not set");
8fc2fb56
WS
2032 }
2033
2034 reply = dbus_message_new_method_return(message);
a0caebf3
JM
2035 if (!reply)
2036 return wpas_dbus_error_no_memory(message);
8fc2fb56
WS
2037
2038 dbus_message_iter_init_append(reply, &iter);
2039
2040 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
5228401c 2041 DBUS_TYPE_BYTE_AS_STRING,
a0caebf3
JM
2042 &array_iter) ||
2043 !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
2044 &(blob->data), blob->len) ||
2045 !dbus_message_iter_close_container(&iter, &array_iter)) {
8fc2fb56 2046 dbus_message_unref(reply);
a0caebf3 2047 reply = wpas_dbus_error_no_memory(message);
8fc2fb56
WS
2048 }
2049
8fc2fb56 2050 return reply;
8fc2fb56
WS
2051}
2052
2053
2054/**
2055 * wpas_remove_handler_remove_blob - Remove named binary blob
2056 * @message: Pointer to incoming dbus message
2057 * @wpa_s: %wpa_supplicant data structure
2058 * Returns: NULL on success or dbus error
2059 *
2060 * Asks wpa_supplicant to internally remove a binary blobs.
2061 */
2062DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
5228401c 2063 struct wpa_supplicant *wpa_s)
8fc2fb56
WS
2064{
2065 DBusMessage *reply = NULL;
8fc2fb56
WS
2066 char *blob_name;
2067
2068 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
5228401c 2069 DBUS_TYPE_INVALID);
8fc2fb56
WS
2070
2071 if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
5228401c
JM
2072 return dbus_message_new_error(message,
2073 WPAS_DBUS_ERROR_BLOB_UNKNOWN,
2074 "Blob id not set");
8fc2fb56
WS
2075 }
2076 wpas_notify_blob_removed(wpa_s, blob_name);
2077
2078 return reply;
2079
2080}
2081
21f01a8e
JM
2082#endif /* CONFIG_NO_CONFIG_BLOBS */
2083
2084
2b65b30d
SL
2085/*
2086 * wpas_dbus_handler_flush_bss - Flush the BSS cache
2087 * @message: Pointer to incoming dbus message
2088 * @wpa_s: wpa_supplicant structure for a network interface
2089 * Returns: NULL
2090 *
2091 * Handler function for "FlushBSS" method call of network interface.
2092 */
2093DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
2094 struct wpa_supplicant *wpa_s)
2095{
2096 dbus_uint32_t age;
2097
2098 dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
2099 DBUS_TYPE_INVALID);
2100
2101 if (age == 0)
2102 wpa_bss_flush(wpa_s);
2103 else
2104 wpa_bss_flush_by_age(wpa_s, age);
2105
2106 return NULL;
2107}
2108
8fc2fb56 2109
67892d5c
TB
2110#ifdef CONFIG_AUTOSCAN
2111/**
2112 * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
2113 * @message: Pointer to incoming dbus message
2114 * @wpa_s: wpa_supplicant structure for a network interface
2115 * Returns: NULL
2116 *
2117 * Handler function for "AutoScan" method call of network interface.
2118 */
2119DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
2120 struct wpa_supplicant *wpa_s)
2121{
2122 DBusMessage *reply = NULL;
2123 enum wpa_states state = wpa_s->wpa_state;
2124 char *arg;
2125
2126 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
2127 DBUS_TYPE_INVALID);
2128
2129 if (arg != NULL && os_strlen(arg) > 0) {
2130 char *tmp;
38279bdb 2131
67892d5c
TB
2132 tmp = os_strdup(arg);
2133 if (tmp == NULL) {
a0caebf3 2134 reply = wpas_dbus_error_no_memory(message);
67892d5c
TB
2135 } else {
2136 os_free(wpa_s->conf->autoscan);
2137 wpa_s->conf->autoscan = tmp;
2138 if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
99218999 2139 autoscan_init(wpa_s, 1);
99f00324
JM
2140 else if (state == WPA_SCANNING)
2141 wpa_supplicant_reinit_autoscan(wpa_s);
67892d5c
TB
2142 }
2143 } else if (arg != NULL && os_strlen(arg) == 0) {
2144 os_free(wpa_s->conf->autoscan);
2145 wpa_s->conf->autoscan = NULL;
2146 autoscan_deinit(wpa_s);
2147 } else
2148 reply = dbus_message_new_error(message,
2149 DBUS_ERROR_INVALID_ARGS,
2150 NULL);
2151
2152 return reply;
2153}
2154#endif /* CONFIG_AUTOSCAN */
2155
2156
754632c9
PS
2157/*
2158 * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
2159 * @message: Pointer to incoming dbus message
2160 * @wpa_s: wpa_supplicant structure for a network interface
2161 * Returns: NULL
2162 *
2163 * Handler function for "EAPLogoff" method call of network interface.
2164 */
2165DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
2166 struct wpa_supplicant *wpa_s)
2167{
2168 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
2169 return NULL;
2170}
2171
2172
2173/*
2174 * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
2175 * @message: Pointer to incoming dbus message
2176 * @wpa_s: wpa_supplicant structure for a network interface
2177 * Returns: NULL
2178 *
2179 * Handler function for "EAPLogin" method call of network interface.
2180 */
2181DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
2182 struct wpa_supplicant *wpa_s)
2183{
2184 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
2185 return NULL;
2186}
2187
2188
cea97a04
PS
2189#ifdef CONFIG_TDLS
2190
508e24c2
JM
2191static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
2192 u8 *peer_address, DBusMessage **error)
cea97a04
PS
2193{
2194 const char *peer_string;
2195
508e24c2
JM
2196 *error = NULL;
2197
cea97a04
PS
2198 if (!dbus_message_get_args(message, NULL,
2199 DBUS_TYPE_STRING, &peer_string,
508e24c2
JM
2200 DBUS_TYPE_INVALID)) {
2201 *error = wpas_dbus_error_invalid_args(message, NULL);
2202 return -1;
2203 }
cea97a04
PS
2204
2205 if (hwaddr_aton(peer_string, peer_address)) {
2206 wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
2207 func_name, peer_string);
508e24c2 2208 *error = wpas_dbus_error_invalid_args(
cea97a04 2209 message, "Invalid hardware address format");
508e24c2 2210 return -1;
cea97a04
PS
2211 }
2212
508e24c2 2213 return 0;
cea97a04
PS
2214}
2215
2216
2217/*
2218 * wpas_dbus_handler_tdls_discover - Discover TDLS peer
2219 * @message: Pointer to incoming dbus message
2220 * @wpa_s: wpa_supplicant structure for a network interface
2221 * Returns: NULL indicating success or DBus error message on failure
2222 *
2223 * Handler function for "TDLSDiscover" method call of network interface.
2224 */
2225DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
2226 struct wpa_supplicant *wpa_s)
2227{
2228 u8 peer[ETH_ALEN];
2229 DBusMessage *error_reply;
2230 int ret;
2231
508e24c2 2232 if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
cea97a04
PS
2233 return error_reply;
2234
2235 wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
2236
2237 if (wpa_tdls_is_external_setup(wpa_s->wpa))
2238 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
2239 else
2240 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
2241
2242 if (ret) {
2243 return wpas_dbus_error_unknown_error(
2244 message, "error performing TDLS discovery");
2245 }
2246
2247 return NULL;
2248}
2249
2250
2251/*
2252 * wpas_dbus_handler_tdls_setup - Setup TDLS session
2253 * @message: Pointer to incoming dbus message
2254 * @wpa_s: wpa_supplicant structure for a network interface
2255 * Returns: NULL indicating success or DBus error message on failure
2256 *
2257 * Handler function for "TDLSSetup" method call of network interface.
2258 */
2259DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
2260 struct wpa_supplicant *wpa_s)
2261{
2262 u8 peer[ETH_ALEN];
2263 DBusMessage *error_reply;
2264 int ret;
2265
508e24c2 2266 if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
cea97a04
PS
2267 return error_reply;
2268
2269 wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
2270
2271 wpa_tdls_remove(wpa_s->wpa, peer);
2272 if (wpa_tdls_is_external_setup(wpa_s->wpa))
2273 ret = wpa_tdls_start(wpa_s->wpa, peer);
2274 else
2275 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2276
2277 if (ret) {
2278 return wpas_dbus_error_unknown_error(
2279 message, "error performing TDLS setup");
2280 }
2281
2282 return NULL;
2283}
2284
2285
2286/*
2287 * wpas_dbus_handler_tdls_status - Return TDLS session status
2288 * @message: Pointer to incoming dbus message
2289 * @wpa_s: wpa_supplicant structure for a network interface
2290 * Returns: A string representing the state of the link to this TDLS peer
2291 *
2292 * Handler function for "TDLSStatus" method call of network interface.
2293 */
2294DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
2295 struct wpa_supplicant *wpa_s)
2296{
2297 u8 peer[ETH_ALEN];
2298 DBusMessage *reply;
2299 const char *tdls_status;
2300
508e24c2 2301 if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
cea97a04
PS
2302 return reply;
2303
2304 wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
2305
2306 tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
2307
2308 reply = dbus_message_new_method_return(message);
2309 dbus_message_append_args(reply, DBUS_TYPE_STRING,
2310 &tdls_status, DBUS_TYPE_INVALID);
2311 return reply;
2312}
2313
2314
2315/*
2316 * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
2317 * @message: Pointer to incoming dbus message
2318 * @wpa_s: wpa_supplicant structure for a network interface
2319 * Returns: NULL indicating success or DBus error message on failure
2320 *
2321 * Handler function for "TDLSTeardown" method call of network interface.
2322 */
2323DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
2324 struct wpa_supplicant *wpa_s)
2325{
2326 u8 peer[ETH_ALEN];
2327 DBusMessage *error_reply;
2328 int ret;
2329
508e24c2 2330 if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
cea97a04
PS
2331 return error_reply;
2332
2333 wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
2334
2335 if (wpa_tdls_is_external_setup(wpa_s->wpa))
2336 ret = wpa_tdls_teardown_link(
2337 wpa_s->wpa, peer,
2338 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
2339 else
2340 ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
2341
2342 if (ret) {
2343 return wpas_dbus_error_unknown_error(
2344 message, "error performing TDLS teardown");
2345 }
2346
2347 return NULL;
2348}
2349
2a57b4b8
NC
2350/*
2351 * wpas_dbus_handler_tdls_channel_switch - Enable channel switching with TDLS peer
2352 * @message: Pointer to incoming dbus message
2353 * @wpa_s: wpa_supplicant structure for a network interface
2354 * Returns: NULL indicating success or DBus error message on failure
2355 *
2356 * Handler function for "TDLSChannelSwitch" method call of network interface.
2357 */
2358DBusMessage *
2359wpas_dbus_handler_tdls_channel_switch(DBusMessage *message,
2360 struct wpa_supplicant *wpa_s)
2361{
2362 DBusMessageIter iter, iter_dict;
2363 struct wpa_dbus_dict_entry entry;
2364 u8 peer[ETH_ALEN];
2365 struct hostapd_freq_params freq_params;
2366 u8 oper_class = 0;
2367 int ret;
2368 int is_peer_present = 0;
2369
2370 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
2371 wpa_printf(MSG_INFO,
2372 "tdls_chanswitch: Only supported with external setup");
2373 return wpas_dbus_error_unknown_error(message, "TDLS is not using external setup");
2374 }
2375
2376 os_memset(&freq_params, 0, sizeof(freq_params));
2377
2378 dbus_message_iter_init(message, &iter);
2379
2380 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2381 return wpas_dbus_error_invalid_args(message, NULL);
2382
2383 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2384 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2385 return wpas_dbus_error_invalid_args(message, NULL);
2386
2387 if (os_strcmp(entry.key, "PeerAddress") == 0 &&
2388 entry.type == DBUS_TYPE_STRING) {
2389 if (hwaddr_aton(entry.str_value, peer)) {
2390 wpa_printf(MSG_DEBUG,
2391 "tdls_chanswitch: Invalid address '%s'",
2392 entry.str_value);
2393 wpa_dbus_dict_entry_clear(&entry);
2394 return wpas_dbus_error_invalid_args(message,
2395 NULL);
2396 }
2397
2398 is_peer_present = 1;
2399 } else if (os_strcmp(entry.key, "OperClass") == 0 &&
2400 entry.type == DBUS_TYPE_BYTE) {
2401 oper_class = entry.byte_value;
2402 } else if (os_strcmp(entry.key, "Frequency") == 0 &&
2403 entry.type == DBUS_TYPE_UINT32) {
2404 freq_params.freq = entry.uint32_value;
2405 } else if (os_strcmp(entry.key, "SecChannelOffset") == 0 &&
2406 entry.type == DBUS_TYPE_UINT32) {
2407 freq_params.sec_channel_offset = entry.uint32_value;
2408 } else if (os_strcmp(entry.key, "CenterFrequency1") == 0 &&
2409 entry.type == DBUS_TYPE_UINT32) {
2410 freq_params.center_freq1 = entry.uint32_value;
2411 } else if (os_strcmp(entry.key, "CenterFrequency2") == 0 &&
2412 entry.type == DBUS_TYPE_UINT32) {
2413 freq_params.center_freq2 = entry.uint32_value;
2414 } else if (os_strcmp(entry.key, "Bandwidth") == 0 &&
2415 entry.type == DBUS_TYPE_UINT32) {
2416 freq_params.bandwidth = entry.uint32_value;
2417 } else if (os_strcmp(entry.key, "HT") == 0 &&
2418 entry.type == DBUS_TYPE_BOOLEAN) {
2419 freq_params.ht_enabled = entry.bool_value;
2420 } else if (os_strcmp(entry.key, "VHT") == 0 &&
2421 entry.type == DBUS_TYPE_BOOLEAN) {
2422 freq_params.vht_enabled = entry.bool_value;
2423 } else {
2424 wpa_dbus_dict_entry_clear(&entry);
2425 return wpas_dbus_error_invalid_args(message, NULL);
2426 }
2427
2428 wpa_dbus_dict_entry_clear(&entry);
2429 }
2430
2431 if (oper_class == 0) {
2432 wpa_printf(MSG_INFO,
2433 "tdls_chanswitch: Invalid op class provided");
2434 return wpas_dbus_error_invalid_args(
2435 message, "Invalid op class provided");
2436 }
2437
2438 if (freq_params.freq == 0) {
2439 wpa_printf(MSG_INFO,
2440 "tdls_chanswitch: Invalid freq provided");
2441 return wpas_dbus_error_invalid_args(message,
2442 "Invalid freq provided");
2443 }
2444
2445 if (is_peer_present == 0) {
2446 wpa_printf(MSG_DEBUG,
2447 "tdls_chanswitch: peer address not provided");
2448 return wpas_dbus_error_invalid_args(
2449 message, "peer address not provided");
2450 }
2451
2452 wpa_printf(MSG_DEBUG, "dbus: TDLS_CHAN_SWITCH " MACSTR
2453 " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
2454 MAC2STR(peer), oper_class, freq_params.freq,
2455 freq_params.center_freq1, freq_params.center_freq2,
2456 freq_params.bandwidth, freq_params.sec_channel_offset,
2457 freq_params.ht_enabled ? " HT" : "",
2458 freq_params.vht_enabled ? " VHT" : "");
2459
2460 ret = wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
2461 &freq_params);
2462 if (ret)
2463 return wpas_dbus_error_unknown_error(
2464 message, "error processing TDLS channel switch");
2465
2466 return NULL;
2467}
2468
9f494746
NC
2469/*
2470 * wpas_dbus_handler_tdls_cancel_channel_switch - Disable channel switching with TDLS peer
2471 * @message: Pointer to incoming dbus message
2472 * @wpa_s: wpa_supplicant structure for a network interface
2473 * Returns: NULL indicating success or DBus error message on failure
2474 *
2475 * Handler function for "TDLSCancelChannelSwitch" method call of network
2476 * interface.
2477 */
2478DBusMessage *
2479wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message,
2480 struct wpa_supplicant *wpa_s)
2481{
2482 u8 peer[ETH_ALEN];
2483 DBusMessage *error_reply;
2484 int ret;
2485
2486 if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2487 return error_reply;
2488
2489 wpa_printf(MSG_DEBUG, "dbus: TDLS_CANCEL_CHAN_SWITCH " MACSTR,
2490 MAC2STR(peer));
2491
2492 ret = wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
2493 if (ret)
2494 return wpas_dbus_error_unknown_error(
2495 message, "error canceling TDLS channel switch");
2496
2497 return NULL;
2498}
2499
cea97a04
PS
2500#endif /* CONFIG_TDLS */
2501
2502
2d0fe6bc
PK
2503#ifndef CONFIG_NO_CONFIG_WRITE
2504/**
2505 * wpas_dbus_handler_save_config - Save configuration to configuration file
2506 * @message: Pointer to incoming dbus message
2507 * @wpa_s: wpa_supplicant structure for a network interface
2508 * Returns: NULL on Success, Otherwise errror message
2509 *
2510 * Handler function for "SaveConfig" method call of network interface.
2511 */
2512DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
2513 struct wpa_supplicant *wpa_s)
2514{
2515 int ret;
2516
2517 if (!wpa_s->conf->update_config) {
2518 return wpas_dbus_error_unknown_error(
2519 message,
2520 "Not allowed to update configuration (update_config=0)");
2521 }
2522
2523 ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
2524 if (ret)
2525 return wpas_dbus_error_unknown_error(
2526 message, "Failed to update configuration");
2527 return NULL;
2528}
2529#endif /* CONFIG_NO_CONFIG_WRITE */
2530
2531
bdec7ee5
MS
2532/**
2533 * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
2534 * @message: Pointer to incoming dbus message
2535 * @wpa_s: %wpa_supplicant data structure
2536 * Returns: A dbus message containing an error on failure or NULL on success
2537 *
2538 * Sets the PKCS #11 engine and module path.
2539 */
2540DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
2541 DBusMessage *message, struct wpa_supplicant *wpa_s)
2542{
2543 DBusMessageIter iter;
2544 char *value = NULL;
2545 char *pkcs11_engine_path = NULL;
2546 char *pkcs11_module_path = NULL;
2547
2548 dbus_message_iter_init(message, &iter);
2549 dbus_message_iter_get_basic(&iter, &value);
2550 if (value == NULL) {
2551 return dbus_message_new_error(
2552 message, DBUS_ERROR_INVALID_ARGS,
2553 "Invalid pkcs11_engine_path argument");
2554 }
2555 /* Empty path defaults to NULL */
2556 if (os_strlen(value))
2557 pkcs11_engine_path = value;
2558
2559 dbus_message_iter_next(&iter);
2560 dbus_message_iter_get_basic(&iter, &value);
2561 if (value == NULL) {
2562 os_free(pkcs11_engine_path);
2563 return dbus_message_new_error(
2564 message, DBUS_ERROR_INVALID_ARGS,
2565 "Invalid pkcs11_module_path argument");
2566 }
2567 /* Empty path defaults to NULL */
2568 if (os_strlen(value))
2569 pkcs11_module_path = value;
2570
2571 if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
2572 pkcs11_module_path))
2573 return dbus_message_new_error(
2574 message, DBUS_ERROR_FAILED,
38279bdb 2575 "Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
bdec7ee5 2576
8a78e227
JM
2577 if (wpa_s->dbus_new_path) {
2578 wpa_dbus_mark_property_changed(
2579 wpa_s->global->dbus, wpa_s->dbus_new_path,
2580 WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
2581 wpa_dbus_mark_property_changed(
2582 wpa_s->global->dbus, wpa_s->dbus_new_path,
2583 WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
2584 }
bdec7ee5
MS
2585
2586 return NULL;
2587}
2588
2589
8fc2fb56
WS
2590/**
2591 * wpas_dbus_getter_capabilities - Return interface capabilities
6aeeb6fa
DW
2592 * @iter: Pointer to incoming dbus message iter
2593 * @error: Location to store error on failure
2594 * @user_data: Function specific data
2595 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
2596 *
2597 * Getter for "Capabilities" property of an interface.
2598 */
1aa0fb77
DW
2599dbus_bool_t wpas_dbus_getter_capabilities(
2600 const struct wpa_dbus_property_desc *property_desc,
2601 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 2602{
6aeeb6fa 2603 struct wpa_supplicant *wpa_s = user_data;
8fc2fb56
WS
2604 struct wpa_driver_capa capa;
2605 int res;
6aeeb6fa 2606 DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
5228401c
JM
2607 variant_iter;
2608 const char *scans[] = { "active", "passive", "ssid" };
8fc2fb56 2609
6aeeb6fa 2610 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
e3c4f0b5
JM
2611 "a{sv}", &variant_iter) ||
2612 !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
8fc2fb56
WS
2613 goto nomem;
2614
2615 res = wpa_drv_get_capa(wpa_s, &capa);
2616
2617 /***** pairwise cipher */
2618 if (res < 0) {
2619 const char *args[] = {"ccmp", "tkip", "none"};
38279bdb 2620
8fc2fb56 2621 if (!wpa_dbus_dict_append_string_array(
5228401c 2622 &iter_dict, "Pairwise", args,
e7ecab4a 2623 ARRAY_SIZE(args)))
8fc2fb56
WS
2624 goto nomem;
2625 } else {
2626 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
2627 &iter_dict_entry,
2628 &iter_dict_val,
e3c4f0b5
JM
2629 &iter_array) ||
2630 ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2631 !wpa_dbus_dict_string_array_add_element(
2632 &iter_array, "ccmp-256")) ||
2633 ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2634 !wpa_dbus_dict_string_array_add_element(
2635 &iter_array, "gcmp-256")) ||
2636 ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2637 !wpa_dbus_dict_string_array_add_element(
2638 &iter_array, "ccmp")) ||
2639 ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2640 !wpa_dbus_dict_string_array_add_element(
2641 &iter_array, "gcmp")) ||
2642 ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2643 !wpa_dbus_dict_string_array_add_element(
2644 &iter_array, "tkip")) ||
2645 ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2646 !wpa_dbus_dict_string_array_add_element(
2647 &iter_array, "none")) ||
2648 !wpa_dbus_dict_end_string_array(&iter_dict,
8fc2fb56
WS
2649 &iter_dict_entry,
2650 &iter_dict_val,
2651 &iter_array))
2652 goto nomem;
2653 }
2654
2655 /***** group cipher */
2656 if (res < 0) {
2657 const char *args[] = {
2658 "ccmp", "tkip", "wep104", "wep40"
2659 };
38279bdb 2660
8fc2fb56 2661 if (!wpa_dbus_dict_append_string_array(
5228401c 2662 &iter_dict, "Group", args,
e7ecab4a 2663 ARRAY_SIZE(args)))
8fc2fb56
WS
2664 goto nomem;
2665 } else {
2666 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
2667 &iter_dict_entry,
2668 &iter_dict_val,
e3c4f0b5
JM
2669 &iter_array) ||
2670 ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2671 !wpa_dbus_dict_string_array_add_element(
2672 &iter_array, "ccmp-256")) ||
2673 ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2674 !wpa_dbus_dict_string_array_add_element(
2675 &iter_array, "gcmp-256")) ||
2676 ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2677 !wpa_dbus_dict_string_array_add_element(
2678 &iter_array, "ccmp")) ||
2679 ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2680 !wpa_dbus_dict_string_array_add_element(
2681 &iter_array, "gcmp")) ||
2682 ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2683 !wpa_dbus_dict_string_array_add_element(
2684 &iter_array, "tkip")) ||
2685 ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
2686 !wpa_dbus_dict_string_array_add_element(
2687 &iter_array, "wep104")) ||
2688 ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
2689 !wpa_dbus_dict_string_array_add_element(
2690 &iter_array, "wep40")) ||
2691 !wpa_dbus_dict_end_string_array(&iter_dict,
8fc2fb56
WS
2692 &iter_dict_entry,
2693 &iter_dict_val,
2694 &iter_array))
2695 goto nomem;
2696 }
2697
117875db
JM
2698 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "GroupMgmt",
2699 &iter_dict_entry,
2700 &iter_dict_val,
2701 &iter_array) ||
2702 (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP) &&
2703 !wpa_dbus_dict_string_array_add_element(
2704 &iter_array, "aes-128-cmac")) ||
2705 (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_128) &&
2706 !wpa_dbus_dict_string_array_add_element(
2707 &iter_array, "bip-gmac-128")) ||
2708 (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_256) &&
2709 !wpa_dbus_dict_string_array_add_element(
2710 &iter_array, "bip-gmac-256")) ||
2711 (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_CMAC_256) &&
2712 !wpa_dbus_dict_string_array_add_element(
2713 &iter_array, "bip-cmac-256")) ||
2714 !wpa_dbus_dict_end_string_array(&iter_dict,
2715 &iter_dict_entry,
2716 &iter_dict_val,
2717 &iter_array))
2718 goto nomem;
2719
8fc2fb56
WS
2720 /***** key management */
2721 if (res < 0) {
2722 const char *args[] = {
2723 "wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
2724#ifdef CONFIG_WPS
2725 "wps",
2726#endif /* CONFIG_WPS */
2727 "none"
2728 };
2729 if (!wpa_dbus_dict_append_string_array(
5228401c 2730 &iter_dict, "KeyMgmt", args,
e7ecab4a 2731 ARRAY_SIZE(args)))
8fc2fb56
WS
2732 goto nomem;
2733 } else {
2734 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
2735 &iter_dict_entry,
2736 &iter_dict_val,
e3c4f0b5
JM
2737 &iter_array) ||
2738 !wpa_dbus_dict_string_array_add_element(&iter_array,
2739 "none") ||
2740 !wpa_dbus_dict_string_array_add_element(&iter_array,
8fc2fb56
WS
2741 "ieee8021x"))
2742 goto nomem;
2743
2744 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2745 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2746 if (!wpa_dbus_dict_string_array_add_element(
e3c4f0b5
JM
2747 &iter_array, "wpa-eap") ||
2748 ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
2749 !wpa_dbus_dict_string_array_add_element(
2750 &iter_array, "wpa-ft-eap")))
8fc2fb56 2751 goto nomem;
c56ce48a 2752
c56ce48a 2753/* TODO: Ensure that driver actually supports sha256 encryption. */
c56ce48a
WS
2754 if (!wpa_dbus_dict_string_array_add_element(
2755 &iter_array, "wpa-eap-sha256"))
2756 goto nomem;
8fc2fb56
WS
2757 }
2758
2759 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2760 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2761 if (!wpa_dbus_dict_string_array_add_element(
e3c4f0b5
JM
2762 &iter_array, "wpa-psk") ||
2763 ((capa.key_mgmt &
2764 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
2765 !wpa_dbus_dict_string_array_add_element(
2766 &iter_array, "wpa-ft-psk")))
8fc2fb56 2767 goto nomem;
c56ce48a 2768
c56ce48a 2769/* TODO: Ensure that driver actually supports sha256 encryption. */
c56ce48a
WS
2770 if (!wpa_dbus_dict_string_array_add_element(
2771 &iter_array, "wpa-psk-sha256"))
2772 goto nomem;
8fc2fb56
WS
2773 }
2774
e3c4f0b5
JM
2775 if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2776 !wpa_dbus_dict_string_array_add_element(&iter_array,
2777 "wpa-none"))
2778 goto nomem;
8fc2fb56
WS
2779
2780
2781#ifdef CONFIG_WPS
5228401c
JM
2782 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2783 "wps"))
8fc2fb56
WS
2784 goto nomem;
2785#endif /* CONFIG_WPS */
2786
2787 if (!wpa_dbus_dict_end_string_array(&iter_dict,
2788 &iter_dict_entry,
2789 &iter_dict_val,
2790 &iter_array))
2791 goto nomem;
8fc2fb56
WS
2792 }
2793
2794 /***** WPA protocol */
2795 if (res < 0) {
2796 const char *args[] = { "rsn", "wpa" };
38279bdb 2797
8fc2fb56 2798 if (!wpa_dbus_dict_append_string_array(
5228401c 2799 &iter_dict, "Protocol", args,
e7ecab4a 2800 ARRAY_SIZE(args)))
8fc2fb56
WS
2801 goto nomem;
2802 } else {
2803 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
2804 &iter_dict_entry,
2805 &iter_dict_val,
e3c4f0b5
JM
2806 &iter_array) ||
2807 ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2808 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
2809 !wpa_dbus_dict_string_array_add_element(
2810 &iter_array, "rsn")) ||
2811 ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2812 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
2813 !wpa_dbus_dict_string_array_add_element(
2814 &iter_array, "wpa")) ||
2815 !wpa_dbus_dict_end_string_array(&iter_dict,
8fc2fb56
WS
2816 &iter_dict_entry,
2817 &iter_dict_val,
2818 &iter_array))
2819 goto nomem;
2820 }
2821
2822 /***** auth alg */
2823 if (res < 0) {
2824 const char *args[] = { "open", "shared", "leap" };
38279bdb 2825
8fc2fb56 2826 if (!wpa_dbus_dict_append_string_array(
5228401c 2827 &iter_dict, "AuthAlg", args,
e7ecab4a 2828 ARRAY_SIZE(args)))
8fc2fb56
WS
2829 goto nomem;
2830 } else {
2831 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
2832 &iter_dict_entry,
2833 &iter_dict_val,
2834 &iter_array))
2835 goto nomem;
2836
e3c4f0b5
JM
2837 if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
2838 !wpa_dbus_dict_string_array_add_element(
2839 &iter_array, "open")) ||
2840 ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
2841 !wpa_dbus_dict_string_array_add_element(
2842 &iter_array, "shared")) ||
2843 ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
2844 !wpa_dbus_dict_string_array_add_element(
2845 &iter_array, "leap")) ||
2846 !wpa_dbus_dict_end_string_array(&iter_dict,
8fc2fb56
WS
2847 &iter_dict_entry,
2848 &iter_dict_val,
2849 &iter_array))
2850 goto nomem;
2851 }
2852
2853 /***** Scan */
5228401c 2854 if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
e7ecab4a 2855 ARRAY_SIZE(scans)))
8fc2fb56
WS
2856 goto nomem;
2857
2858 /***** Modes */
c988980d
JS
2859 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
2860 &iter_dict_entry,
2861 &iter_dict_val,
e3c4f0b5
JM
2862 &iter_array) ||
2863 !wpa_dbus_dict_string_array_add_element(
2864 &iter_array, "infrastructure") ||
e8a1b6b8
SB
2865 (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) &&
2866 !wpa_dbus_dict_string_array_add_element(
2867 &iter_array, "ad-hoc")) ||
e3c4f0b5
JM
2868 (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
2869 !wpa_dbus_dict_string_array_add_element(
2870 &iter_array, "ap")) ||
2871 (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
f91e11f4 2872 !wpa_s->conf->p2p_disabled &&
e3c4f0b5
JM
2873 !wpa_dbus_dict_string_array_add_element(
2874 &iter_array, "p2p")) ||
d02989f2
SB
2875#ifdef CONFIG_MESH
2876 (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_MESH) &&
2877 !wpa_dbus_dict_string_array_add_element(
2878 &iter_array, "mesh")) ||
2879#endif /* CONFIG_MESH */
e3c4f0b5 2880 !wpa_dbus_dict_end_string_array(&iter_dict,
c988980d
JS
2881 &iter_dict_entry,
2882 &iter_dict_val,
2883 &iter_array))
2884 goto nomem;
2885 /***** Modes end */
2886
0098ce6d
MA
2887 if (res >= 0) {
2888 dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
2889
2890 if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
2891 max_scan_ssid))
2892 goto nomem;
2893 }
2894
e3c4f0b5
JM
2895 if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
2896 !dbus_message_iter_close_container(iter, &variant_iter))
8fc2fb56
WS
2897 goto nomem;
2898
6aeeb6fa 2899 return TRUE;
8fc2fb56
WS
2900
2901nomem:
6aeeb6fa
DW
2902 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2903 return FALSE;
8fc2fb56
WS
2904}
2905
2906
2907/**
2908 * wpas_dbus_getter_state - Get interface state
6aeeb6fa
DW
2909 * @iter: Pointer to incoming dbus message iter
2910 * @error: Location to store error on failure
2911 * @user_data: Function specific data
2912 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
2913 *
2914 * Getter for "State" property.
2915 */
1aa0fb77
DW
2916dbus_bool_t wpas_dbus_getter_state(
2917 const struct wpa_dbus_property_desc *property_desc,
2918 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 2919{
6aeeb6fa 2920 struct wpa_supplicant *wpa_s = user_data;
8fc2fb56
WS
2921 const char *str_state;
2922 char *state_ls, *tmp;
6aeeb6fa 2923 dbus_bool_t success = FALSE;
8fc2fb56 2924
fcea0b7d 2925 str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
8fc2fb56 2926
fcea0b7d
WS
2927 /* make state string lowercase to fit new DBus API convention
2928 */
2929 state_ls = tmp = os_strdup(str_state);
2930 if (!tmp) {
6aeeb6fa
DW
2931 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2932 return FALSE;
fcea0b7d
WS
2933 }
2934 while (*tmp) {
2935 *tmp = tolower(*tmp);
2936 tmp++;
2937 }
8fc2fb56 2938
6aeeb6fa
DW
2939 success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2940 &state_ls, error);
8fc2fb56 2941
fcea0b7d 2942 os_free(state_ls);
5228401c 2943
6aeeb6fa 2944 return success;
8fc2fb56
WS
2945}
2946
fcea0b7d 2947
8fc2fb56
WS
2948/**
2949 * wpas_dbus_new_iface_get_scanning - Get interface scanning state
6aeeb6fa
DW
2950 * @iter: Pointer to incoming dbus message iter
2951 * @error: Location to store error on failure
2952 * @user_data: Function specific data
2953 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
2954 *
2955 * Getter for "scanning" property.
2956 */
1aa0fb77
DW
2957dbus_bool_t wpas_dbus_getter_scanning(
2958 const struct wpa_dbus_property_desc *property_desc,
2959 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 2960{
6aeeb6fa 2961 struct wpa_supplicant *wpa_s = user_data;
8fc2fb56 2962 dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
6aeeb6fa
DW
2963
2964 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2965 &scanning, error);
fcea0b7d 2966}
8fc2fb56
WS
2967
2968
2969/**
2970 * wpas_dbus_getter_ap_scan - Control roaming mode
6aeeb6fa
DW
2971 * @iter: Pointer to incoming dbus message iter
2972 * @error: Location to store error on failure
2973 * @user_data: Function specific data
2974 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
2975 *
2976 * Getter function for "ApScan" property.
2977 */
1aa0fb77
DW
2978dbus_bool_t wpas_dbus_getter_ap_scan(
2979 const struct wpa_dbus_property_desc *property_desc,
2980 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 2981{
6aeeb6fa 2982 struct wpa_supplicant *wpa_s = user_data;
8fc2fb56 2983 dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
6aeeb6fa
DW
2984
2985 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2986 &ap_scan, error);
8fc2fb56
WS
2987}
2988
2989
2990/**
2991 * wpas_dbus_setter_ap_scan - Control roaming mode
6aeeb6fa
DW
2992 * @iter: Pointer to incoming dbus message iter
2993 * @error: Location to store error on failure
2994 * @user_data: Function specific data
2995 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
2996 *
2997 * Setter function for "ApScan" property.
2998 */
1aa0fb77
DW
2999dbus_bool_t wpas_dbus_setter_ap_scan(
3000 const struct wpa_dbus_property_desc *property_desc,
3001 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 3002{
6aeeb6fa 3003 struct wpa_supplicant *wpa_s = user_data;
8fc2fb56
WS
3004 dbus_uint32_t ap_scan;
3005
6aeeb6fa
DW
3006 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3007 &ap_scan))
3008 return FALSE;
8fc2fb56
WS
3009
3010 if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
6aeeb6fa
DW
3011 dbus_set_error_const(error, DBUS_ERROR_FAILED,
3012 "ap_scan must be 0, 1, or 2");
3013 return FALSE;
8fc2fb56 3014 }
6aeeb6fa 3015 return TRUE;
8fc2fb56
WS
3016}
3017
3018
a4bbb606
PS
3019/**
3020 * wpas_dbus_getter_fast_reauth - Control fast
3021 * reauthentication (TLS session resumption)
3022 * @iter: Pointer to incoming dbus message iter
3023 * @error: Location to store error on failure
3024 * @user_data: Function specific data
3025 * Returns: TRUE on success, FALSE on failure
3026 *
3027 * Getter function for "FastReauth" property.
3028 */
1aa0fb77
DW
3029dbus_bool_t wpas_dbus_getter_fast_reauth(
3030 const struct wpa_dbus_property_desc *property_desc,
3031 DBusMessageIter *iter, DBusError *error, void *user_data)
a4bbb606
PS
3032{
3033 struct wpa_supplicant *wpa_s = user_data;
3034 dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
3035
3036 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3037 &fast_reauth, error);
3038}
3039
3040
3041/**
3042 * wpas_dbus_setter_fast_reauth - Control fast
3043 * reauthentication (TLS session resumption)
3044 * @iter: Pointer to incoming dbus message iter
3045 * @error: Location to store error on failure
3046 * @user_data: Function specific data
3047 * Returns: TRUE on success, FALSE on failure
3048 *
3049 * Setter function for "FastReauth" property.
3050 */
1aa0fb77
DW
3051dbus_bool_t wpas_dbus_setter_fast_reauth(
3052 const struct wpa_dbus_property_desc *property_desc,
3053 DBusMessageIter *iter, DBusError *error, void *user_data)
a4bbb606
PS
3054{
3055 struct wpa_supplicant *wpa_s = user_data;
3056 dbus_bool_t fast_reauth;
3057
3058 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
3059 &fast_reauth))
3060 return FALSE;
3061
3062 wpa_s->conf->fast_reauth = fast_reauth;
3063 return TRUE;
3064}
3065
3066
0bb1e425
GM
3067/**
3068 * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
3069 * @iter: Pointer to incoming dbus message iter
3070 * @error: Location to store error on failure
3071 * @user_data: Function specific data
3072 * Returns: TRUE on success, FALSE on failure
3073 *
3074 * Getter for "DisconnectReason" property. The reason is negative if it is
3075 * locally generated.
3076 */
1aa0fb77
DW
3077dbus_bool_t wpas_dbus_getter_disconnect_reason(
3078 const struct wpa_dbus_property_desc *property_desc,
3079 DBusMessageIter *iter, DBusError *error, void *user_data)
0bb1e425
GM
3080{
3081 struct wpa_supplicant *wpa_s = user_data;
3082 dbus_int32_t reason = wpa_s->disconnect_reason;
38279bdb 3083
0bb1e425
GM
3084 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3085 &reason, error);
3086}
3087
3088
38b405c8
AK
3089/**
3090 * wpas_dbus_getter_auth_status_code - Get most recent auth status code
3091 * @iter: Pointer to incoming dbus message iter
3092 * @error: Location to store error on failure
3093 * @user_data: Function specific data
3094 * Returns: TRUE on success, FALSE on failure
3095 *
3096 * Getter for "AuthStatusCode" property.
3097 */
3098dbus_bool_t wpas_dbus_getter_auth_status_code(
3099 const struct wpa_dbus_property_desc *property_desc,
3100 DBusMessageIter *iter, DBusError *error, void *user_data)
3101{
3102 struct wpa_supplicant *wpa_s = user_data;
3103 dbus_int32_t reason = wpa_s->auth_status_code;
3104
3105 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3106 &reason, error);
3107}
3108
3109
c7fb678f
NS
3110/**
3111 * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code
3112 * @iter: Pointer to incoming dbus message iter
3113 * @error: Location to store error on failure
3114 * @user_data: Function specific data
3115 * Returns: TRUE on success, FALSE on failure
3116 *
3117 * Getter for "AssocStatusCode" property.
3118 */
3119dbus_bool_t wpas_dbus_getter_assoc_status_code(
3120 const struct wpa_dbus_property_desc *property_desc,
3121 DBusMessageIter *iter, DBusError *error, void *user_data)
3122{
3123 struct wpa_supplicant *wpa_s = user_data;
3124 dbus_int32_t status_code = wpa_s->assoc_status_code;
3125
3126 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3127 &status_code, error);
3128}
3129
3130
2bbad1c7
MW
3131/**
3132 * wpas_dbus_getter_roam_time - Get most recent roam time
3133 * @iter: Pointer to incoming dbus message iter
3134 * @error: Location to store error on failure
3135 * @user_data: Function specific data
3136 * Returns: TRUE on success, FALSE on failure
3137 *
3138 * Getter for "RoamTime" property.
3139 */
3140dbus_bool_t wpas_dbus_getter_roam_time(
3141 const struct wpa_dbus_property_desc *property_desc,
3142 DBusMessageIter *iter, DBusError *error, void *user_data)
3143{
3144 struct wpa_supplicant *wpa_s = user_data;
3145 dbus_uint32_t roam_time = wpa_s->roam_time.sec * 1000 +
3146 wpa_s->roam_time.usec / 1000;
3147
3148 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3149 &roam_time, error);
3150}
3151
3152
3153/**
3154 * wpas_dbus_getter_roam_complete - Get most recent roam success or failure
3155 * @iter: Pointer to incoming dbus message iter
3156 * @error: Location to store error on failure
3157 * @user_data: Function specific data
3158 * Returns: TRUE on success, FALSE on failure
3159 *
3160 * Getter for "RoamComplete" property.
3161 */
3162dbus_bool_t wpas_dbus_getter_roam_complete(
3163 const struct wpa_dbus_property_desc *property_desc,
3164 DBusMessageIter *iter, DBusError *error, void *user_data)
3165{
3166 struct wpa_supplicant *wpa_s = user_data;
3167 dbus_bool_t roam_complete = os_reltime_initialized(&wpa_s->roam_time);
3168
3169 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3170 &roam_complete, error);
3171}
3172
3173
3174/**
3175 * wpas_dbus_getter_session_length - Get most recent BSS session length
3176 * @iter: Pointer to incoming dbus message iter
3177 * @error: Location to store error on failure
3178 * @user_data: Function specific data
3179 * Returns: TRUE on success, FALSE on failure
3180 *
3181 * Getter for "SessionLength" property.
3182 */
3183dbus_bool_t wpas_dbus_getter_session_length(
3184 const struct wpa_dbus_property_desc *property_desc,
3185 DBusMessageIter *iter, DBusError *error, void *user_data)
3186{
3187 struct wpa_supplicant *wpa_s = user_data;
3188 dbus_uint32_t session_length = wpa_s->session_length.sec * 1000 +
3189 wpa_s->session_length.usec / 1000;
3190
3191 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3192 &session_length, error);
3193}
3194
3195
80d06d0c
MW
3196/**
3197 * wpas_dbus_getter_bss_tm_status - Get most BSS Transition Management request
3198 * status code
3199 * @iter: Pointer to incoming dbus message iter
3200 * @error: Location to store error on failure
3201 * @user_data: Function specific data
3202 * Returns: TRUE on success, FALSE on failure
3203 *
3204 * Getter for "BSSTMStatus" property.
3205 */
3206dbus_bool_t wpas_dbus_getter_bss_tm_status(
3207 const struct wpa_dbus_property_desc *property_desc,
3208 DBusMessageIter *iter, DBusError *error, void *user_data)
3209{
441ba1a3 3210#ifdef CONFIG_WNM
80d06d0c
MW
3211 struct wpa_supplicant *wpa_s = user_data;
3212 dbus_uint32_t bss_tm_status = wpa_s->bss_tm_status;
441ba1a3
JM
3213#else /* CONFIG_WNM */
3214 dbus_uint32_t bss_tm_status = 0;
3215#endif /* CONFIG_WNM */
80d06d0c
MW
3216
3217 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3218 &bss_tm_status, error);
3219}
3220
3221
78633c37
SL
3222/**
3223 * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
6aeeb6fa
DW
3224 * @iter: Pointer to incoming dbus message iter
3225 * @error: Location to store error on failure
3226 * @user_data: Function specific data
3227 * Returns: TRUE on success, FALSE on failure
78633c37
SL
3228 *
3229 * Getter function for "BSSExpireAge" property.
3230 */
1aa0fb77
DW
3231dbus_bool_t wpas_dbus_getter_bss_expire_age(
3232 const struct wpa_dbus_property_desc *property_desc,
3233 DBusMessageIter *iter, DBusError *error, void *user_data)
78633c37 3234{
6aeeb6fa 3235 struct wpa_supplicant *wpa_s = user_data;
78633c37 3236 dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
6aeeb6fa
DW
3237
3238 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3239 &expire_age, error);
78633c37
SL
3240}
3241
3242
3243/**
3244 * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
6aeeb6fa
DW
3245 * @iter: Pointer to incoming dbus message iter
3246 * @error: Location to store error on failure
3247 * @user_data: Function specific data
3248 * Returns: TRUE on success, FALSE on failure
78633c37
SL
3249 *
3250 * Setter function for "BSSExpireAge" property.
3251 */
1aa0fb77
DW
3252dbus_bool_t wpas_dbus_setter_bss_expire_age(
3253 const struct wpa_dbus_property_desc *property_desc,
3254 DBusMessageIter *iter, DBusError *error, void *user_data)
78633c37 3255{
6aeeb6fa 3256 struct wpa_supplicant *wpa_s = user_data;
78633c37
SL
3257 dbus_uint32_t expire_age;
3258
6aeeb6fa
DW
3259 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3260 &expire_age))
3261 return FALSE;
78633c37
SL
3262
3263 if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
6aeeb6fa
DW
3264 dbus_set_error_const(error, DBUS_ERROR_FAILED,
3265 "BSSExpireAge must be >= 10");
3266 return FALSE;
78633c37 3267 }
6aeeb6fa 3268 return TRUE;
78633c37
SL
3269}
3270
3271
3272/**
3273 * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
6aeeb6fa
DW
3274 * @iter: Pointer to incoming dbus message iter
3275 * @error: Location to store error on failure
3276 * @user_data: Function specific data
3277 * Returns: TRUE on success, FALSE on failure
78633c37
SL
3278 *
3279 * Getter function for "BSSExpireCount" property.
3280 */
1aa0fb77
DW
3281dbus_bool_t wpas_dbus_getter_bss_expire_count(
3282 const struct wpa_dbus_property_desc *property_desc,
3283 DBusMessageIter *iter, DBusError *error, void *user_data)
78633c37 3284{
6aeeb6fa 3285 struct wpa_supplicant *wpa_s = user_data;
c10fe8c1 3286 dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
6aeeb6fa
DW
3287
3288 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3289 &expire_count, error);
78633c37
SL
3290}
3291
3292
3293/**
3294 * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
6aeeb6fa
DW
3295 * @iter: Pointer to incoming dbus message iter
3296 * @error: Location to store error on failure
3297 * @user_data: Function specific data
3298 * Returns: TRUE on success, FALSE on failure
78633c37
SL
3299 *
3300 * Setter function for "BSSExpireCount" property.
3301 */
1aa0fb77
DW
3302dbus_bool_t wpas_dbus_setter_bss_expire_count(
3303 const struct wpa_dbus_property_desc *property_desc,
3304 DBusMessageIter *iter, DBusError *error, void *user_data)
78633c37 3305{
6aeeb6fa 3306 struct wpa_supplicant *wpa_s = user_data;
78633c37
SL
3307 dbus_uint32_t expire_count;
3308
6aeeb6fa
DW
3309 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3310 &expire_count))
3311 return FALSE;
78633c37
SL
3312
3313 if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
6aeeb6fa
DW
3314 dbus_set_error_const(error, DBUS_ERROR_FAILED,
3315 "BSSExpireCount must be > 0");
3316 return FALSE;
78633c37 3317 }
6aeeb6fa 3318 return TRUE;
78633c37
SL
3319}
3320
3321
9768da20
SL
3322/**
3323 * wpas_dbus_getter_country - Control country code
6aeeb6fa
DW
3324 * @iter: Pointer to incoming dbus message iter
3325 * @error: Location to store error on failure
3326 * @user_data: Function specific data
3327 * Returns: TRUE on success, FALSE on failure
9768da20
SL
3328 *
3329 * Getter function for "Country" property.
3330 */
1aa0fb77
DW
3331dbus_bool_t wpas_dbus_getter_country(
3332 const struct wpa_dbus_property_desc *property_desc,
3333 DBusMessageIter *iter, DBusError *error, void *user_data)
9768da20 3334{
6aeeb6fa 3335 struct wpa_supplicant *wpa_s = user_data;
9768da20
SL
3336 char country[3];
3337 char *str = country;
3338
3339 country[0] = wpa_s->conf->country[0];
3340 country[1] = wpa_s->conf->country[1];
3341 country[2] = '\0';
3342
6aeeb6fa
DW
3343 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3344 &str, error);
9768da20
SL
3345}
3346
3347
3348/**
3349 * wpas_dbus_setter_country - Control country code
6aeeb6fa
DW
3350 * @iter: Pointer to incoming dbus message iter
3351 * @error: Location to store error on failure
3352 * @user_data: Function specific data
3353 * Returns: TRUE on success, FALSE on failure
9768da20
SL
3354 *
3355 * Setter function for "Country" property.
3356 */
1aa0fb77
DW
3357dbus_bool_t wpas_dbus_setter_country(
3358 const struct wpa_dbus_property_desc *property_desc,
3359 DBusMessageIter *iter, DBusError *error, void *user_data)
9768da20 3360{
6aeeb6fa 3361 struct wpa_supplicant *wpa_s = user_data;
9768da20
SL
3362 const char *country;
3363
6aeeb6fa
DW
3364 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
3365 &country))
3366 return FALSE;
9768da20 3367
6aeeb6fa
DW
3368 if (!country[0] || !country[1]) {
3369 dbus_set_error_const(error, DBUS_ERROR_FAILED,
3370 "invalid country code");
3371 return FALSE;
3372 }
9768da20
SL
3373
3374 if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
3375 wpa_printf(MSG_DEBUG, "Failed to set country");
6aeeb6fa
DW
3376 dbus_set_error_const(error, DBUS_ERROR_FAILED,
3377 "failed to set country code");
3378 return FALSE;
9768da20
SL
3379 }
3380
3381 wpa_s->conf->country[0] = country[0];
3382 wpa_s->conf->country[1] = country[1];
6aeeb6fa 3383 return TRUE;
9768da20
SL
3384}
3385
3386
c6e86b63
MA
3387/**
3388 * wpas_dbus_getter_scan_interval - Get scan interval
3389 * @iter: Pointer to incoming dbus message iter
3390 * @error: Location to store error on failure
3391 * @user_data: Function specific data
3392 * Returns: TRUE on success, FALSE on failure
3393 *
3394 * Getter function for "ScanInterval" property.
3395 */
1aa0fb77
DW
3396dbus_bool_t wpas_dbus_getter_scan_interval(
3397 const struct wpa_dbus_property_desc *property_desc,
3398 DBusMessageIter *iter, DBusError *error, void *user_data)
c6e86b63
MA
3399{
3400 struct wpa_supplicant *wpa_s = user_data;
3401 dbus_int32_t scan_interval = wpa_s->scan_interval;
3402
3403 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3404 &scan_interval, error);
3405}
3406
3407
3408/**
3409 * wpas_dbus_setter_scan_interval - Control scan interval
3410 * @iter: Pointer to incoming dbus message iter
3411 * @error: Location to store error on failure
3412 * @user_data: Function specific data
3413 * Returns: TRUE on success, FALSE on failure
3414 *
3415 * Setter function for "ScanInterval" property.
3416 */
1aa0fb77
DW
3417dbus_bool_t wpas_dbus_setter_scan_interval(
3418 const struct wpa_dbus_property_desc *property_desc,
3419 DBusMessageIter *iter, DBusError *error, void *user_data)
c6e86b63
MA
3420{
3421 struct wpa_supplicant *wpa_s = user_data;
3422 dbus_int32_t scan_interval;
3423
3424 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
3425 &scan_interval))
3426 return FALSE;
3427
3428 if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
3429 dbus_set_error_const(error, DBUS_ERROR_FAILED,
3430 "scan_interval must be >= 0");
3431 return FALSE;
3432 }
3433 return TRUE;
3434}
3435
3436
8fc2fb56
WS
3437/**
3438 * wpas_dbus_getter_ifname - Get interface name
6aeeb6fa
DW
3439 * @iter: Pointer to incoming dbus message iter
3440 * @error: Location to store error on failure
3441 * @user_data: Function specific data
3442 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
3443 *
3444 * Getter for "Ifname" property.
3445 */
1aa0fb77
DW
3446dbus_bool_t wpas_dbus_getter_ifname(
3447 const struct wpa_dbus_property_desc *property_desc,
3448 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 3449{
6aeeb6fa 3450 struct wpa_supplicant *wpa_s = user_data;
6aeeb6fa 3451
77fcbf7f 3452 return wpas_dbus_string_property_getter(iter, wpa_s->ifname, error);
8fc2fb56
WS
3453}
3454
3455
3456/**
3457 * wpas_dbus_getter_driver - Get interface name
6aeeb6fa
DW
3458 * @iter: Pointer to incoming dbus message iter
3459 * @error: Location to store error on failure
3460 * @user_data: Function specific data
3461 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
3462 *
3463 * Getter for "Driver" property.
3464 */
1aa0fb77
DW
3465dbus_bool_t wpas_dbus_getter_driver(
3466 const struct wpa_dbus_property_desc *property_desc,
3467 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 3468{
6aeeb6fa 3469 struct wpa_supplicant *wpa_s = user_data;
8fc2fb56
WS
3470
3471 if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
38279bdb
JM
3472 wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
3473 __func__);
6aeeb6fa
DW
3474 dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
3475 __func__);
3476 return FALSE;
8fc2fb56
WS
3477 }
3478
77fcbf7f
JM
3479 return wpas_dbus_string_property_getter(iter, wpa_s->driver->name,
3480 error);
8fc2fb56
WS
3481}
3482
3483
3484/**
3485 * wpas_dbus_getter_current_bss - Get current bss object path
6aeeb6fa
DW
3486 * @iter: Pointer to incoming dbus message iter
3487 * @error: Location to store error on failure
3488 * @user_data: Function specific data
3489 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
3490 *
3491 * Getter for "CurrentBSS" property.
3492 */
1aa0fb77
DW
3493dbus_bool_t wpas_dbus_getter_current_bss(
3494 const struct wpa_dbus_property_desc *property_desc,
3495 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 3496{
6aeeb6fa 3497 struct wpa_supplicant *wpa_s = user_data;
3e87bd54 3498 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
8fc2fb56 3499
8a78e227 3500 if (wpa_s->current_bss && wpa_s->dbus_new_path)
5228401c 3501 os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
ccd286d0 3502 "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
8f770587 3503 wpa_s->dbus_new_path, wpa_s->current_bss->id);
8fc2fb56 3504 else
5228401c 3505 os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
8fc2fb56 3506
6aeeb6fa
DW
3507 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3508 &bss_obj_path, error);
8fc2fb56
WS
3509}
3510
3511
3512/**
3513 * wpas_dbus_getter_current_network - Get current network object path
6aeeb6fa
DW
3514 * @iter: Pointer to incoming dbus message iter
3515 * @error: Location to store error on failure
3516 * @user_data: Function specific data
3517 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
3518 *
3519 * Getter for "CurrentNetwork" property.
3520 */
1aa0fb77
DW
3521dbus_bool_t wpas_dbus_getter_current_network(
3522 const struct wpa_dbus_property_desc *property_desc,
3523 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 3524{
6aeeb6fa 3525 struct wpa_supplicant *wpa_s = user_data;
3e87bd54 3526 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
8fc2fb56 3527
8a78e227 3528 if (wpa_s->current_ssid && wpa_s->dbus_new_path)
5228401c 3529 os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
c49cf2d6
JM
3530 "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
3531 wpa_s->dbus_new_path, wpa_s->current_ssid->id);
8fc2fb56 3532 else
5228401c 3533 os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
8fc2fb56 3534
6aeeb6fa
DW
3535 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3536 &net_obj_path, error);
8fc2fb56
WS
3537}
3538
3539
ba6f267f
PS
3540/**
3541 * wpas_dbus_getter_current_auth_mode - Get current authentication type
6aeeb6fa
DW
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
ba6f267f
PS
3546 *
3547 * Getter for "CurrentAuthMode" property.
3548 */
1aa0fb77
DW
3549dbus_bool_t wpas_dbus_getter_current_auth_mode(
3550 const struct wpa_dbus_property_desc *property_desc,
3551 DBusMessageIter *iter, DBusError *error, void *user_data)
ba6f267f 3552{
6aeeb6fa 3553 struct wpa_supplicant *wpa_s = user_data;
ba6f267f
PS
3554 const char *eap_mode;
3555 const char *auth_mode;
3556 char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
3557
3558 if (wpa_s->wpa_state != WPA_COMPLETED) {
3559 auth_mode = "INACTIVE";
3560 } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
3561 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3562 eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
3563 os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
3564 "EAP-%s", eap_mode);
3565 auth_mode = eap_mode_buf;
3566
fc1e2c0d 3567 } else if (wpa_s->current_ssid) {
ba6f267f
PS
3568 auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
3569 wpa_s->current_ssid->proto);
fc1e2c0d
JM
3570 } else {
3571 auth_mode = "UNKNOWN";
ba6f267f
PS
3572 }
3573
6aeeb6fa
DW
3574 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3575 &auth_mode, error);
ba6f267f
PS
3576}
3577
3578
8fc2fb56
WS
3579/**
3580 * wpas_dbus_getter_bridge_ifname - Get interface name
6aeeb6fa
DW
3581 * @iter: Pointer to incoming dbus message iter
3582 * @error: Location to store error on failure
3583 * @user_data: Function specific data
3584 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
3585 *
3586 * Getter for "BridgeIfname" property.
3587 */
1aa0fb77
DW
3588dbus_bool_t wpas_dbus_getter_bridge_ifname(
3589 const struct wpa_dbus_property_desc *property_desc,
3590 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 3591{
6aeeb6fa 3592 struct wpa_supplicant *wpa_s = user_data;
38279bdb 3593
77fcbf7f
JM
3594 return wpas_dbus_string_property_getter(iter, wpa_s->bridge_ifname,
3595 error);
8fc2fb56
WS
3596}
3597
3598
b44d9c76
JB
3599/**
3600 * wpas_dbus_getter_config_file - Get interface configuration file path
3601 * @iter: Pointer to incoming dbus message iter
3602 * @error: Location to store error on failure
3603 * @user_data: Function specific data
3604 * Returns: TRUE on success, FALSE on failure
3605 *
3606 * Getter for "ConfigFile" property.
3607 */
3608dbus_bool_t wpas_dbus_getter_config_file(
3609 const struct wpa_dbus_property_desc *property_desc,
3610 DBusMessageIter *iter, DBusError *error, void *user_data)
3611{
3612 struct wpa_supplicant *wpa_s = user_data;
b44d9c76 3613
77fcbf7f 3614 return wpas_dbus_string_property_getter(iter, wpa_s->confname, error);
b44d9c76
JB
3615}
3616
3617
8fc2fb56
WS
3618/**
3619 * wpas_dbus_getter_bsss - Get array of BSSs objects
6aeeb6fa
DW
3620 * @iter: Pointer to incoming dbus message iter
3621 * @error: Location to store error on failure
3622 * @user_data: Function specific data
3623 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
3624 *
3625 * Getter for "BSSs" property.
3626 */
1aa0fb77
DW
3627dbus_bool_t wpas_dbus_getter_bsss(
3628 const struct wpa_dbus_property_desc *property_desc,
3629 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 3630{
6aeeb6fa 3631 struct wpa_supplicant *wpa_s = user_data;
ccd286d0 3632 struct wpa_bss *bss;
fcea0b7d
WS
3633 char **paths;
3634 unsigned int i = 0;
6aeeb6fa 3635 dbus_bool_t success = FALSE;
8fc2fb56 3636
8a78e227
JM
3637 if (!wpa_s->dbus_new_path) {
3638 dbus_set_error(error, DBUS_ERROR_FAILED,
3639 "%s: no D-Bus interface", __func__);
3640 return FALSE;
3641 }
3642
f9884c09 3643 paths = os_calloc(wpa_s->num_bss, sizeof(char *));
fcea0b7d 3644 if (!paths) {
6aeeb6fa
DW
3645 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3646 return FALSE;
8fc2fb56
WS
3647 }
3648
3649 /* Loop through scan results and append each result's object path */
ccd286d0 3650 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
fcea0b7d
WS
3651 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3652 if (paths[i] == NULL) {
6aeeb6fa
DW
3653 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3654 "no memory");
8fc2fb56
WS
3655 goto out;
3656 }
ccd286d0 3657 /* Construct the object path for this BSS. */
fcea0b7d 3658 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
ccd286d0 3659 "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
c49cf2d6 3660 wpa_s->dbus_new_path, bss->id);
8fc2fb56
WS
3661 }
3662
6aeeb6fa
DW
3663 success = wpas_dbus_simple_array_property_getter(iter,
3664 DBUS_TYPE_OBJECT_PATH,
3665 paths, wpa_s->num_bss,
3666 error);
8fc2fb56
WS
3667
3668out:
3e87bd54 3669 while (i)
fcea0b7d
WS
3670 os_free(paths[--i]);
3671 os_free(paths);
6aeeb6fa 3672 return success;
8fc2fb56
WS
3673}
3674
3675
3676/**
3677 * wpas_dbus_getter_networks - Get array of networks objects
6aeeb6fa
DW
3678 * @iter: Pointer to incoming dbus message iter
3679 * @error: Location to store error on failure
3680 * @user_data: Function specific data
3681 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
3682 *
3683 * Getter for "Networks" property.
3684 */
1aa0fb77
DW
3685dbus_bool_t wpas_dbus_getter_networks(
3686 const struct wpa_dbus_property_desc *property_desc,
3687 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 3688{
6aeeb6fa 3689 struct wpa_supplicant *wpa_s = user_data;
8fc2fb56 3690 struct wpa_ssid *ssid;
fcea0b7d
WS
3691 char **paths;
3692 unsigned int i = 0, num = 0;
6aeeb6fa 3693 dbus_bool_t success = FALSE;
8fc2fb56 3694
8a78e227
JM
3695 if (!wpa_s->dbus_new_path) {
3696 dbus_set_error(error, DBUS_ERROR_FAILED,
3697 "%s: no D-Bus interface", __func__);
3698 return FALSE;
3699 }
3700
fcea0b7d 3701 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
c2762e41
JS
3702 if (!network_is_persistent_group(ssid))
3703 num++;
8fc2fb56 3704
f9884c09 3705 paths = os_calloc(num, sizeof(char *));
fcea0b7d 3706 if (!paths) {
6aeeb6fa
DW
3707 dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3708 return FALSE;
8fc2fb56
WS
3709 }
3710
fcea0b7d 3711 /* Loop through configured networks and append object path of each */
8fc2fb56 3712 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
c2762e41
JS
3713 if (network_is_persistent_group(ssid))
3714 continue;
fcea0b7d
WS
3715 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3716 if (paths[i] == NULL) {
38279bdb
JM
3717 dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
3718 "no memory");
8fc2fb56
WS
3719 goto out;
3720 }
3721
3722 /* Construct the object path for this network. */
fcea0b7d 3723 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
5228401c 3724 "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
c49cf2d6 3725 wpa_s->dbus_new_path, ssid->id);
8fc2fb56
WS
3726 }
3727
6aeeb6fa
DW
3728 success = wpas_dbus_simple_array_property_getter(iter,
3729 DBUS_TYPE_OBJECT_PATH,
3730 paths, num, error);
8fc2fb56
WS
3731
3732out:
fcea0b7d
WS
3733 while (i)
3734 os_free(paths[--i]);
3735 os_free(paths);
6aeeb6fa 3736 return success;
8fc2fb56
WS
3737}
3738
3739
bdec7ee5
MS
3740/**
3741 * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
3742 * @iter: Pointer to incoming dbus message iter
3743 * @error: Location to store error on failure
3744 * @user_data: Function specific data
3745 * Returns: A dbus message containing the PKCS #11 engine path
3746 *
3747 * Getter for "PKCS11EnginePath" property.
3748 */
1aa0fb77
DW
3749dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(
3750 const struct wpa_dbus_property_desc *property_desc,
3751 DBusMessageIter *iter, DBusError *error, void *user_data)
bdec7ee5
MS
3752{
3753 struct wpa_supplicant *wpa_s = user_data;
bdec7ee5 3754
77fcbf7f
JM
3755 return wpas_dbus_string_property_getter(iter,
3756 wpa_s->conf->pkcs11_engine_path,
3757 error);
bdec7ee5
MS
3758}
3759
3760
3761/**
3762 * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
3763 * @iter: Pointer to incoming dbus message iter
3764 * @error: Location to store error on failure
3765 * @user_data: Function specific data
3766 * Returns: A dbus message containing the PKCS #11 module path
3767 *
3768 * Getter for "PKCS11ModulePath" property.
3769 */
1aa0fb77
DW
3770dbus_bool_t wpas_dbus_getter_pkcs11_module_path(
3771 const struct wpa_dbus_property_desc *property_desc,
3772 DBusMessageIter *iter, DBusError *error, void *user_data)
bdec7ee5
MS
3773{
3774 struct wpa_supplicant *wpa_s = user_data;
bdec7ee5 3775
77fcbf7f
JM
3776 return wpas_dbus_string_property_getter(iter,
3777 wpa_s->conf->pkcs11_module_path,
3778 error);
bdec7ee5
MS
3779}
3780
3781
8fc2fb56
WS
3782/**
3783 * wpas_dbus_getter_blobs - Get all blobs defined for this interface
6aeeb6fa
DW
3784 * @iter: Pointer to incoming dbus message iter
3785 * @error: Location to store error on failure
3786 * @user_data: Function specific data
3787 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
3788 *
3789 * Getter for "Blobs" property.
3790 */
1aa0fb77
DW
3791dbus_bool_t wpas_dbus_getter_blobs(
3792 const struct wpa_dbus_property_desc *property_desc,
3793 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 3794{
6aeeb6fa
DW
3795 struct wpa_supplicant *wpa_s = user_data;
3796 DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
8fc2fb56
WS
3797 struct wpa_config_blob *blob;
3798
6aeeb6fa 3799 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
c2b8c674
JM
3800 "a{say}", &variant_iter) ||
3801 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
5228401c 3802 "{say}", &dict_iter)) {
6aeeb6fa
DW
3803 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3804 return FALSE;
8fc2fb56
WS
3805 }
3806
3807 blob = wpa_s->conf->blobs;
3808 while (blob) {
5228401c
JM
3809 if (!dbus_message_iter_open_container(&dict_iter,
3810 DBUS_TYPE_DICT_ENTRY,
c2b8c674
JM
3811 NULL, &entry_iter) ||
3812 !dbus_message_iter_append_basic(&entry_iter,
5228401c 3813 DBUS_TYPE_STRING,
c2b8c674
JM
3814 &(blob->name)) ||
3815 !dbus_message_iter_open_container(&entry_iter,
5228401c
JM
3816 DBUS_TYPE_ARRAY,
3817 DBUS_TYPE_BYTE_AS_STRING,
c2b8c674
JM
3818 &array_iter) ||
3819 !dbus_message_iter_append_fixed_array(&array_iter,
5228401c
JM
3820 DBUS_TYPE_BYTE,
3821 &(blob->data),
c2b8c674
JM
3822 blob->len) ||
3823 !dbus_message_iter_close_container(&entry_iter,
3824 &array_iter) ||
3825 !dbus_message_iter_close_container(&dict_iter,
5228401c 3826 &entry_iter)) {
6aeeb6fa
DW
3827 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3828 "no memory");
3829 return FALSE;
8fc2fb56
WS
3830 }
3831
3832 blob = blob->next;
3833 }
3834
c2b8c674 3835 if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
6aeeb6fa
DW
3836 !dbus_message_iter_close_container(iter, &variant_iter)) {
3837 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3838 return FALSE;
8fc2fb56
WS
3839 }
3840
6aeeb6fa
DW
3841 return TRUE;
3842}
3843
3844
e50c50d5
DW
3845dbus_bool_t wpas_dbus_getter_iface_global(
3846 const struct wpa_dbus_property_desc *property_desc,
3847 DBusMessageIter *iter, DBusError *error, void *user_data)
3848{
3849 struct wpa_supplicant *wpa_s = user_data;
3850 int ret;
3851 char buf[250];
3852 char *p = buf;
3853
3854 if (!property_desc->data) {
3855 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
3856 "Unhandled interface property %s",
3857 property_desc->dbus_property);
3858 return FALSE;
3859 }
3860
3861 ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf,
3862 sizeof(buf));
3863 if (ret < 0)
3864 *p = '\0';
3865
3866 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p,
3867 error);
3868}
3869
3870
3871dbus_bool_t wpas_dbus_setter_iface_global(
3872 const struct wpa_dbus_property_desc *property_desc,
3873 DBusMessageIter *iter, DBusError *error, void *user_data)
3874{
3875 struct wpa_supplicant *wpa_s = user_data;
3876 const char *new_value = NULL;
3877 char buf[250];
3878 size_t combined_len;
3879 int ret;
3880
3881 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
3882 &new_value))
3883 return FALSE;
3884
3885 combined_len = os_strlen(property_desc->data) + os_strlen(new_value) +
3886 3;
3887 if (combined_len >= sizeof(buf)) {
3888 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
3889 "Interface property %s value too large",
3890 property_desc->dbus_property);
3891 return FALSE;
3892 }
3893
3894 if (!new_value[0])
3895 new_value = "NULL";
3896
3897 ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data,
3898 new_value);
3899 if (os_snprintf_error(combined_len, ret)) {
3900 dbus_set_error(error, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
3901 "Failed to construct new interface property %s",
3902 property_desc->dbus_property);
3903 return FALSE;
3904 }
3905
3906 if (wpa_config_process_global(wpa_s->conf, buf, -1)) {
3907 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
3908 "Failed to set interface property %s",
3909 property_desc->dbus_property);
3910 return FALSE;
3911 }
3912
3913 wpa_supplicant_update_config(wpa_s);
3914 return TRUE;
3915}
3916
3917
c3f23ad6
AS
3918/**
3919 * wpas_dbus_getter_stas - Get connected stations for an interface
3920 * @iter: Pointer to incoming dbus message iter
3921 * @error: Location to store error on failure
3922 * @user_data: Function specific data
3923 * Returns: a list of stations
3924 *
3925 * Getter for "Stations" property.
3926 */
3927dbus_bool_t wpas_dbus_getter_stas(
3928 const struct wpa_dbus_property_desc *property_desc,
3929 DBusMessageIter *iter, DBusError *error, void *user_data)
3930{
3931 struct wpa_supplicant *wpa_s = user_data;
c3f23ad6
AS
3932 struct sta_info *sta = NULL;
3933 char **paths = NULL;
3934 unsigned int i = 0, num = 0;
3935 dbus_bool_t success = FALSE;
3936
3937 if (!wpa_s->dbus_new_path) {
3938 dbus_set_error(error, DBUS_ERROR_FAILED,
3939 "%s: no D-Bus interface", __func__);
3940 return FALSE;
3941 }
3942
1b8ed2ca 3943#ifdef CONFIG_AP
c3f23ad6 3944 if (wpa_s->ap_iface) {
1b8ed2ca
MP
3945 struct hostapd_data *hapd;
3946
c3f23ad6
AS
3947 hapd = wpa_s->ap_iface->bss[0];
3948 sta = hapd->sta_list;
3949 num = hapd->num_sta;
3950 }
1b8ed2ca 3951#endif /* CONFIG_AP */
c3f23ad6
AS
3952
3953 paths = os_calloc(num, sizeof(char *));
3954 if (!paths) {
3955 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3956 return FALSE;
3957 }
3958
3959 /* Loop through scan results and append each result's object path */
3960 for (; sta; sta = sta->next) {
3961 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3962 if (!paths[i]) {
3963 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3964 "no memory");
3965 goto out;
3966 }
3967 /* Construct the object path for this BSS. */
3968 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3969 "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
3970 wpa_s->dbus_new_path, MAC2STR(sta->addr));
3971 }
3972
3973 success = wpas_dbus_simple_array_property_getter(iter,
3974 DBUS_TYPE_OBJECT_PATH,
3975 paths, num,
3976 error);
3977
3978out:
3979 while (i)
3980 os_free(paths[--i]);
3981 os_free(paths);
3982 return success;
3983}
3984
3985
3986/**
3987 * wpas_dbus_getter_sta_address - Return the address of a connected station
3988 * @iter: Pointer to incoming dbus message iter
3989 * @error: Location to store error on failure
3990 * @user_data: Function specific data
3991 * Returns: TRUE on success, FALSE on failure
3992 *
3993 * Getter for "Address" property.
3994 */
3995dbus_bool_t wpas_dbus_getter_sta_address(
3996 const struct wpa_dbus_property_desc *property_desc,
3997 DBusMessageIter *iter, DBusError *error, void *user_data)
3998{
1b8ed2ca 3999#ifdef CONFIG_AP
c3f23ad6
AS
4000 struct sta_handler_args *args = user_data;
4001 struct sta_info *sta;
4002
4003 sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4004 if (!sta)
4005 return FALSE;
4006
4007 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4008 sta->addr, ETH_ALEN,
4009 error);
1b8ed2ca
MP
4010#else /* CONFIG_AP */
4011 return FALSE;
4012#endif /* CONFIG_AP */
c3f23ad6
AS
4013}
4014
4015
4016/**
4017 * wpas_dbus_getter_sta_aid - Return the AID of a connected station
4018 * @iter: Pointer to incoming dbus message iter
4019 * @error: Location to store error on failure
4020 * @user_data: Function specific data
4021 * Returns: TRUE on success, FALSE on failure
4022 *
4023 * Getter for "AID" property.
4024 */
4025dbus_bool_t wpas_dbus_getter_sta_aid(
4026 const struct wpa_dbus_property_desc *property_desc,
4027 DBusMessageIter *iter, DBusError *error, void *user_data)
4028{
1b8ed2ca 4029#ifdef CONFIG_AP
c3f23ad6
AS
4030 struct sta_handler_args *args = user_data;
4031 struct sta_info *sta;
4032
4033 sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4034 if (!sta)
4035 return FALSE;
4036
4037 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4038 &sta->aid,
4039 error);
1b8ed2ca
MP
4040#else /* CONFIG_AP */
4041 return FALSE;
4042#endif /* CONFIG_AP */
c3f23ad6
AS
4043}
4044
4045
4046/**
4047 * wpas_dbus_getter_sta_caps - Return the capabilities of a station
4048 * @iter: Pointer to incoming dbus message iter
4049 * @error: Location to store error on failure
4050 * @user_data: Function specific data
4051 * Returns: TRUE on success, FALSE on failure
4052 *
4053 * Getter for "Capabilities" property.
4054 */
4055dbus_bool_t wpas_dbus_getter_sta_caps(
4056 const struct wpa_dbus_property_desc *property_desc,
4057 DBusMessageIter *iter, DBusError *error, void *user_data)
4058{
1b8ed2ca 4059#ifdef CONFIG_AP
c3f23ad6
AS
4060 struct sta_handler_args *args = user_data;
4061 struct sta_info *sta;
4062
4063 sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4064 if (!sta)
4065 return FALSE;
4066
4067 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4068 &sta->capability,
4069 error);
1b8ed2ca
MP
4070#else /* CONFIG_AP */
4071 return FALSE;
4072#endif /* CONFIG_AP */
c3f23ad6
AS
4073}
4074
4075
4076/**
4077 * wpas_dbus_getter_rx_packets - Return the received packets for a station
4078 * @iter: Pointer to incoming dbus message iter
4079 * @error: Location to store error on failure
4080 * @user_data: Function specific data
4081 * Returns: TRUE on success, FALSE on failure
4082 *
4083 * Getter for "RxPackets" property.
4084 */
4085dbus_bool_t wpas_dbus_getter_sta_rx_packets(
4086 const struct wpa_dbus_property_desc *property_desc,
4087 DBusMessageIter *iter, DBusError *error, void *user_data)
4088{
1b8ed2ca 4089#ifdef CONFIG_AP
c3f23ad6
AS
4090 struct sta_handler_args *args = user_data;
4091 struct sta_info *sta;
4092 struct hostap_sta_driver_data data;
4093 struct hostapd_data *hapd;
4094
4095 if (!args->wpa_s->ap_iface)
4096 return FALSE;
4097
4098 hapd = args->wpa_s->ap_iface->bss[0];
4099 sta = ap_get_sta(hapd, args->sta);
4100 if (!sta)
4101 return FALSE;
4102
4103 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4104 return FALSE;
4105
4106 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4107 &data.rx_packets,
4108 error);
1b8ed2ca
MP
4109#else /* CONFIG_AP */
4110 return FALSE;
4111#endif /* CONFIG_AP */
c3f23ad6
AS
4112}
4113
4114
4115/**
4116 * wpas_dbus_getter_tx_packets - Return the transmitted packets for a station
4117 * @iter: Pointer to incoming dbus message iter
4118 * @error: Location to store error on failure
4119 * @user_data: Function specific data
4120 * Returns: TRUE on success, FALSE on failure
4121 *
4122 * Getter for "TxPackets" property.
4123 */
4124dbus_bool_t wpas_dbus_getter_sta_tx_packets(
4125 const struct wpa_dbus_property_desc *property_desc,
4126 DBusMessageIter *iter, DBusError *error, void *user_data)
4127{
1b8ed2ca 4128#ifdef CONFIG_AP
c3f23ad6
AS
4129 struct sta_handler_args *args = user_data;
4130 struct sta_info *sta;
4131 struct hostap_sta_driver_data data;
4132 struct hostapd_data *hapd;
4133
4134 if (!args->wpa_s->ap_iface)
4135 return FALSE;
4136
4137 hapd = args->wpa_s->ap_iface->bss[0];
4138 sta = ap_get_sta(hapd, args->sta);
4139 if (!sta)
4140 return FALSE;
4141
4142 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4143 return FALSE;
4144
4145 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4146 &data.tx_packets,
4147 error);
1b8ed2ca
MP
4148#else /* CONFIG_AP */
4149 return FALSE;
4150#endif /* CONFIG_AP */
c3f23ad6
AS
4151}
4152
4153
4154/**
4155 * wpas_dbus_getter_tx_bytes - Return the transmitted bytes for a station
4156 * @iter: Pointer to incoming dbus message iter
4157 * @error: Location to store error on failure
4158 * @user_data: Function specific data
4159 * Returns: TRUE on success, FALSE on failure
4160 *
4161 * Getter for "TxBytes" property.
4162 */
4163dbus_bool_t wpas_dbus_getter_sta_tx_bytes(
4164 const struct wpa_dbus_property_desc *property_desc,
4165 DBusMessageIter *iter, DBusError *error, void *user_data)
4166{
1b8ed2ca 4167#ifdef CONFIG_AP
c3f23ad6
AS
4168 struct sta_handler_args *args = user_data;
4169 struct sta_info *sta;
4170 struct hostap_sta_driver_data data;
4171 struct hostapd_data *hapd;
4172
4173 if (!args->wpa_s->ap_iface)
4174 return FALSE;
4175
4176 hapd = args->wpa_s->ap_iface->bss[0];
4177 sta = ap_get_sta(hapd, args->sta);
4178 if (!sta)
4179 return FALSE;
4180
4181 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4182 return FALSE;
4183
4184 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4185 &data.tx_bytes,
4186 error);
1b8ed2ca
MP
4187#else /* CONFIG_AP */
4188 return FALSE;
4189#endif /* CONFIG_AP */
c3f23ad6
AS
4190}
4191
4192
4193/**
4194 * wpas_dbus_getter_rx_bytes - Return the received bytes for a station
4195 * @iter: Pointer to incoming dbus message iter
4196 * @error: Location to store error on failure
4197 * @user_data: Function specific data
4198 * Returns: TRUE on success, FALSE on failure
4199 *
4200 * Getter for "RxBytes" property.
4201 */
4202dbus_bool_t wpas_dbus_getter_sta_rx_bytes(
4203 const struct wpa_dbus_property_desc *property_desc,
4204 DBusMessageIter *iter, DBusError *error, void *user_data)
4205{
1b8ed2ca 4206#ifdef CONFIG_AP
c3f23ad6
AS
4207 struct sta_handler_args *args = user_data;
4208 struct sta_info *sta;
4209 struct hostap_sta_driver_data data;
4210 struct hostapd_data *hapd;
4211
4212 if (!args->wpa_s->ap_iface)
4213 return FALSE;
4214
4215 hapd = args->wpa_s->ap_iface->bss[0];
4216 sta = ap_get_sta(hapd, args->sta);
4217 if (!sta)
4218 return FALSE;
4219
4220 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4221 return FALSE;
4222
4223 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4224 &data.rx_bytes,
4225 error);
1b8ed2ca
MP
4226#else /* CONFIG_AP */
4227 return FALSE;
4228#endif /* CONFIG_AP */
c3f23ad6
AS
4229}
4230
4231
6aeeb6fa
DW
4232static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
4233 DBusError *error, const char *func_name)
4234{
4235 struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
4236
4237 if (!res) {
4238 wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
38279bdb 4239 func_name, args->id);
6aeeb6fa
DW
4240 dbus_set_error(error, DBUS_ERROR_FAILED,
4241 "%s: BSS %d not found",
4242 func_name, args->id);
4243 }
4244
4245 return res;
8fc2fb56
WS
4246}
4247
4248
4249/**
58605c6e 4250 * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
6aeeb6fa
DW
4251 * @iter: Pointer to incoming dbus message iter
4252 * @error: Location to store error on failure
4253 * @user_data: Function specific data
4254 * Returns: TRUE on success, FALSE on failure
8fc2fb56 4255 *
58605c6e 4256 * Getter for "BSSID" property.
8fc2fb56 4257 */
1aa0fb77
DW
4258dbus_bool_t wpas_dbus_getter_bss_bssid(
4259 const struct wpa_dbus_property_desc *property_desc,
4260 DBusMessageIter *iter, DBusError *error, void *user_data)
58605c6e 4261{
6aeeb6fa
DW
4262 struct bss_handler_args *args = user_data;
4263 struct wpa_bss *res;
58605c6e 4264
6aeeb6fa
DW
4265 res = get_bss_helper(args, error, __func__);
4266 if (!res)
4267 return FALSE;
58605c6e 4268
6aeeb6fa
DW
4269 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4270 res->bssid, ETH_ALEN,
4271 error);
58605c6e
WS
4272}
4273
4274
4275/**
4276 * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
6aeeb6fa
DW
4277 * @iter: Pointer to incoming dbus message iter
4278 * @error: Location to store error on failure
4279 * @user_data: Function specific data
4280 * Returns: TRUE on success, FALSE on failure
58605c6e
WS
4281 *
4282 * Getter for "SSID" property.
4283 */
1aa0fb77
DW
4284dbus_bool_t wpas_dbus_getter_bss_ssid(
4285 const struct wpa_dbus_property_desc *property_desc,
4286 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 4287{
6aeeb6fa
DW
4288 struct bss_handler_args *args = user_data;
4289 struct wpa_bss *res;
8fc2fb56 4290
6aeeb6fa
DW
4291 res = get_bss_helper(args, error, __func__);
4292 if (!res)
4293 return FALSE;
8fc2fb56 4294
6aeeb6fa
DW
4295 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4296 res->ssid, res->ssid_len,
4297 error);
58605c6e 4298}
8fc2fb56 4299
8fc2fb56 4300
58605c6e
WS
4301/**
4302 * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
6aeeb6fa
DW
4303 * @iter: Pointer to incoming dbus message iter
4304 * @error: Location to store error on failure
4305 * @user_data: Function specific data
4306 * Returns: TRUE on success, FALSE on failure
58605c6e
WS
4307 *
4308 * Getter for "Privacy" property.
4309 */
1aa0fb77
DW
4310dbus_bool_t wpas_dbus_getter_bss_privacy(
4311 const struct wpa_dbus_property_desc *property_desc,
4312 DBusMessageIter *iter, DBusError *error, void *user_data)
58605c6e 4313{
6aeeb6fa
DW
4314 struct bss_handler_args *args = user_data;
4315 struct wpa_bss *res;
58605c6e 4316 dbus_bool_t privacy;
8fc2fb56 4317
6aeeb6fa
DW
4318 res = get_bss_helper(args, error, __func__);
4319 if (!res)
4320 return FALSE;
8fc2fb56 4321
097c5802 4322 privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
6aeeb6fa
DW
4323 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
4324 &privacy, error);
58605c6e 4325}
8fc2fb56 4326
8fc2fb56 4327
58605c6e
WS
4328/**
4329 * wpas_dbus_getter_bss_mode - Return the mode of a BSS
6aeeb6fa
DW
4330 * @iter: Pointer to incoming dbus message iter
4331 * @error: Location to store error on failure
4332 * @user_data: Function specific data
4333 * Returns: TRUE on success, FALSE on failure
58605c6e
WS
4334 *
4335 * Getter for "Mode" property.
4336 */
1aa0fb77
DW
4337dbus_bool_t wpas_dbus_getter_bss_mode(
4338 const struct wpa_dbus_property_desc *property_desc,
4339 DBusMessageIter *iter, DBusError *error, void *user_data)
58605c6e 4340{
6aeeb6fa
DW
4341 struct bss_handler_args *args = user_data;
4342 struct wpa_bss *res;
58605c6e 4343 const char *mode;
213eb188 4344 const u8 *mesh;
58605c6e 4345
6aeeb6fa
DW
4346 res = get_bss_helper(args, error, __func__);
4347 if (!res)
4348 return FALSE;
e403ba85
BS
4349 if (bss_is_dmg(res)) {
4350 switch (res->caps & IEEE80211_CAP_DMG_MASK) {
4351 case IEEE80211_CAP_DMG_PBSS:
4352 case IEEE80211_CAP_DMG_IBSS:
4353 mode = "ad-hoc";
4354 break;
4355 case IEEE80211_CAP_DMG_AP:
4356 mode = "infrastructure";
4357 break;
29065686
JM
4358 default:
4359 mode = "";
4360 break;
e403ba85
BS
4361 }
4362 } else {
213eb188
SB
4363 mesh = wpa_bss_get_ie(res, WLAN_EID_MESH_ID);
4364 if (mesh)
4365 mode = "mesh";
4366 else if (res->caps & IEEE80211_CAP_IBSS)
e403ba85
BS
4367 mode = "ad-hoc";
4368 else
4369 mode = "infrastructure";
4370 }
58605c6e 4371
6aeeb6fa
DW
4372 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
4373 &mode, error);
58605c6e
WS
4374}
4375
4376
4377/**
4378 * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
6aeeb6fa
DW
4379 * @iter: Pointer to incoming dbus message iter
4380 * @error: Location to store error on failure
4381 * @user_data: Function specific data
4382 * Returns: TRUE on success, FALSE on failure
58605c6e
WS
4383 *
4384 * Getter for "Level" property.
4385 */
1aa0fb77
DW
4386dbus_bool_t wpas_dbus_getter_bss_signal(
4387 const struct wpa_dbus_property_desc *property_desc,
4388 DBusMessageIter *iter, DBusError *error, void *user_data)
58605c6e 4389{
6aeeb6fa
DW
4390 struct bss_handler_args *args = user_data;
4391 struct wpa_bss *res;
3d0a8438 4392 s16 level;
58605c6e 4393
6aeeb6fa
DW
4394 res = get_bss_helper(args, error, __func__);
4395 if (!res)
4396 return FALSE;
8fc2fb56 4397
3d0a8438 4398 level = (s16) res->level;
6aeeb6fa 4399 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
3d0a8438 4400 &level, error);
58605c6e
WS
4401}
4402
4403
4404/**
4405 * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
6aeeb6fa
DW
4406 * @iter: Pointer to incoming dbus message iter
4407 * @error: Location to store error on failure
4408 * @user_data: Function specific data
4409 * Returns: TRUE on success, FALSE on failure
58605c6e
WS
4410 *
4411 * Getter for "Frequency" property.
4412 */
1aa0fb77
DW
4413dbus_bool_t wpas_dbus_getter_bss_frequency(
4414 const struct wpa_dbus_property_desc *property_desc,
4415 DBusMessageIter *iter, DBusError *error, void *user_data)
58605c6e 4416{
6aeeb6fa
DW
4417 struct bss_handler_args *args = user_data;
4418 struct wpa_bss *res;
3d0a8438 4419 u16 freq;
58605c6e 4420
6aeeb6fa
DW
4421 res = get_bss_helper(args, error, __func__);
4422 if (!res)
4423 return FALSE;
8fc2fb56 4424
3d0a8438 4425 freq = (u16) res->freq;
6aeeb6fa 4426 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
3d0a8438 4427 &freq, error);
58605c6e
WS
4428}
4429
4430
75d328af
WS
4431static int cmp_u8s_desc(const void *a, const void *b)
4432{
4433 return (*(u8 *) b - *(u8 *) a);
4434}
4435
4436
58605c6e 4437/**
75d328af 4438 * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
6aeeb6fa
DW
4439 * @iter: Pointer to incoming dbus message iter
4440 * @error: Location to store error on failure
4441 * @user_data: Function specific data
4442 * Returns: TRUE on success, FALSE on failure
58605c6e 4443 *
75d328af 4444 * Getter for "Rates" property.
58605c6e 4445 */
1aa0fb77
DW
4446dbus_bool_t wpas_dbus_getter_bss_rates(
4447 const struct wpa_dbus_property_desc *property_desc,
4448 DBusMessageIter *iter, DBusError *error, void *user_data)
58605c6e 4449{
6aeeb6fa
DW
4450 struct bss_handler_args *args = user_data;
4451 struct wpa_bss *res;
75d328af
WS
4452 u8 *ie_rates = NULL;
4453 u32 *real_rates;
4454 int rates_num, i;
6aeeb6fa 4455 dbus_bool_t success = FALSE;
58605c6e 4456
6aeeb6fa
DW
4457 res = get_bss_helper(args, error, __func__);
4458 if (!res)
4459 return FALSE;
8fc2fb56 4460
75d328af
WS
4461 rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
4462 if (rates_num < 0)
6aeeb6fa 4463 return FALSE;
75d328af
WS
4464
4465 qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
4466
4467 real_rates = os_malloc(sizeof(u32) * rates_num);
4468 if (!real_rates) {
4469 os_free(ie_rates);
6aeeb6fa
DW
4470 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4471 return FALSE;
75d328af
WS
4472 }
4473
4474 for (i = 0; i < rates_num; i++)
4475 real_rates[i] = ie_rates[i] * 500000;
4476
6aeeb6fa
DW
4477 success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
4478 real_rates, rates_num,
4479 error);
75d328af
WS
4480
4481 os_free(ie_rates);
4482 os_free(real_rates);
6aeeb6fa 4483 return success;
58605c6e
WS
4484}
4485
4486
1aa0fb77
DW
4487static dbus_bool_t wpas_dbus_get_bss_security_prop(
4488 const struct wpa_dbus_property_desc *property_desc,
4489 DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error)
7899e2f4 4490{
6aeeb6fa 4491 DBusMessageIter iter_dict, variant_iter;
7899e2f4 4492 const char *group;
30675c34 4493 const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
86d4e053 4494 const char *key_mgmt[15]; /* max 15 key managements may be supported */
7899e2f4
WS
4495 int n;
4496
6aeeb6fa 4497 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
7899e2f4
WS
4498 "a{sv}", &variant_iter))
4499 goto nomem;
4500
4501 if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
4502 goto nomem;
4503
98251c6f
LR
4504 /*
4505 * KeyMgmt
4506 *
4507 * When adding a new entry here, please take care to extend key_mgmt[]
4508 * and keep documentation in doc/dbus.doxygen up to date.
4509 */
7899e2f4
WS
4510 n = 0;
4511 if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
4512 key_mgmt[n++] = "wpa-psk";
4513 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
4514 key_mgmt[n++] = "wpa-ft-psk";
4515 if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
4516 key_mgmt[n++] = "wpa-psk-sha256";
4517 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
4518 key_mgmt[n++] = "wpa-eap";
4519 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
4520 key_mgmt[n++] = "wpa-ft-eap";
4521 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
4522 key_mgmt[n++] = "wpa-eap-sha256";
5e3b5197 4523#ifdef CONFIG_SUITEB
666497c8
JM
4524 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
4525 key_mgmt[n++] = "wpa-eap-suite-b";
5e3b5197
JM
4526#endif /* CONFIG_SUITEB */
4527#ifdef CONFIG_SUITEB192
4528 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
4529 key_mgmt[n++] = "wpa-eap-suite-b-192";
4530#endif /* CONFIG_SUITEB192 */
6240424a
MH
4531#ifdef CONFIG_FILS
4532 if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
4533 key_mgmt[n++] = "wpa-fils-sha256";
4534 if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
4535 key_mgmt[n++] = "wpa-fils-sha384";
4536 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
4537 key_mgmt[n++] = "wpa-ft-fils-sha256";
4538 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
4539 key_mgmt[n++] = "wpa-ft-fils-sha384";
4540#endif /* CONFIG_FILS */
86d4e053
LR
4541#ifdef CONFIG_SAE
4542 if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE)
4543 key_mgmt[n++] = "sae";
4544 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
4545 key_mgmt[n++] = "ft-sae";
4546#endif /* CONFIG_SAE */
7899e2f4
WS
4547 if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
4548 key_mgmt[n++] = "wpa-none";
4549
4550 if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
4551 key_mgmt, n))
4552 goto nomem;
4553
4554 /* Group */
4555 switch (ie_data->group_cipher) {
4556 case WPA_CIPHER_WEP40:
4557 group = "wep40";
4558 break;
4559 case WPA_CIPHER_TKIP:
4560 group = "tkip";
4561 break;
4562 case WPA_CIPHER_CCMP:
4563 group = "ccmp";
4564 break;
eb7719ff
JM
4565 case WPA_CIPHER_GCMP:
4566 group = "gcmp";
4567 break;
7899e2f4
WS
4568 case WPA_CIPHER_WEP104:
4569 group = "wep104";
4570 break;
30675c34
JM
4571 case WPA_CIPHER_CCMP_256:
4572 group = "ccmp-256";
4573 break;
4574 case WPA_CIPHER_GCMP_256:
4575 group = "gcmp-256";
4576 break;
7899e2f4
WS
4577 default:
4578 group = "";
4579 break;
4580 }
4581
4582 if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
4583 goto nomem;
4584
4585 /* Pairwise */
4586 n = 0;
4587 if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
4588 pairwise[n++] = "tkip";
4589 if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
4590 pairwise[n++] = "ccmp";
eb7719ff
JM
4591 if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
4592 pairwise[n++] = "gcmp";
30675c34
JM
4593 if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
4594 pairwise[n++] = "ccmp-256";
4595 if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
4596 pairwise[n++] = "gcmp-256";
7899e2f4
WS
4597
4598 if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
4599 pairwise, n))
4600 goto nomem;
4601
4602 /* Management group (RSN only) */
4603 if (ie_data->proto == WPA_PROTO_RSN) {
4604 switch (ie_data->mgmt_group_cipher) {
7899e2f4
WS
4605 case WPA_CIPHER_AES_128_CMAC:
4606 group = "aes128cmac";
4607 break;
7899e2f4
WS
4608 default:
4609 group = "";
4610 break;
4611 }
4612
4613 if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
4614 group))
4615 goto nomem;
4616 }
4617
e3c4f0b5
JM
4618 if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
4619 !dbus_message_iter_close_container(iter, &variant_iter))
7899e2f4
WS
4620 goto nomem;
4621
6aeeb6fa 4622 return TRUE;
7899e2f4
WS
4623
4624nomem:
6aeeb6fa
DW
4625 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4626 return FALSE;
7899e2f4
WS
4627}
4628
4629
58605c6e 4630/**
7899e2f4 4631 * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
6aeeb6fa
DW
4632 * @iter: Pointer to incoming dbus message iter
4633 * @error: Location to store error on failure
4634 * @user_data: Function specific data
4635 * Returns: TRUE on success, FALSE on failure
58605c6e 4636 *
7899e2f4 4637 * Getter for "WPA" property.
58605c6e 4638 */
1aa0fb77
DW
4639dbus_bool_t wpas_dbus_getter_bss_wpa(
4640 const struct wpa_dbus_property_desc *property_desc,
4641 DBusMessageIter *iter, DBusError *error, void *user_data)
58605c6e 4642{
6aeeb6fa
DW
4643 struct bss_handler_args *args = user_data;
4644 struct wpa_bss *res;
7899e2f4 4645 struct wpa_ie_data wpa_data;
58605c6e
WS
4646 const u8 *ie;
4647
6aeeb6fa
DW
4648 res = get_bss_helper(args, error, __func__);
4649 if (!res)
4650 return FALSE;
8fc2fb56 4651
7899e2f4 4652 os_memset(&wpa_data, 0, sizeof(wpa_data));
58605c6e 4653 ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
e3c4f0b5
JM
4654 if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
4655 dbus_set_error_const(error, DBUS_ERROR_FAILED,
4656 "failed to parse WPA IE");
4657 return FALSE;
af3e1b0e 4658 }
7899e2f4 4659
1aa0fb77 4660 return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
58605c6e 4661}
8fc2fb56 4662
8fc2fb56 4663
58605c6e 4664/**
7899e2f4 4665 * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
6aeeb6fa
DW
4666 * @iter: Pointer to incoming dbus message iter
4667 * @error: Location to store error on failure
4668 * @user_data: Function specific data
4669 * Returns: TRUE on success, FALSE on failure
58605c6e 4670 *
7899e2f4 4671 * Getter for "RSN" property.
58605c6e 4672 */
1aa0fb77
DW
4673dbus_bool_t wpas_dbus_getter_bss_rsn(
4674 const struct wpa_dbus_property_desc *property_desc,
4675 DBusMessageIter *iter, DBusError *error, void *user_data)
58605c6e 4676{
6aeeb6fa
DW
4677 struct bss_handler_args *args = user_data;
4678 struct wpa_bss *res;
7899e2f4 4679 struct wpa_ie_data wpa_data;
58605c6e
WS
4680 const u8 *ie;
4681
6aeeb6fa
DW
4682 res = get_bss_helper(args, error, __func__);
4683 if (!res)
4684 return FALSE;
58605c6e 4685
7899e2f4 4686 os_memset(&wpa_data, 0, sizeof(wpa_data));
58605c6e 4687 ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
e3c4f0b5
JM
4688 if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
4689 dbus_set_error_const(error, DBUS_ERROR_FAILED,
4690 "failed to parse RSN IE");
4691 return FALSE;
af3e1b0e 4692 }
7899e2f4 4693
1aa0fb77 4694 return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
58605c6e
WS
4695}
4696
4697
caff3992
SN
4698/**
4699 * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
4700 * @iter: Pointer to incoming dbus message iter
4701 * @error: Location to store error on failure
4702 * @user_data: Function specific data
4703 * Returns: TRUE on success, FALSE on failure
4704 *
4705 * Getter for "WPS" property.
4706 */
1aa0fb77
DW
4707dbus_bool_t wpas_dbus_getter_bss_wps(
4708 const struct wpa_dbus_property_desc *property_desc,
4709 DBusMessageIter *iter, DBusError *error, void *user_data)
caff3992
SN
4710{
4711 struct bss_handler_args *args = user_data;
4712 struct wpa_bss *res;
4713#ifdef CONFIG_WPS
4714 struct wpabuf *wps_ie;
4715#endif /* CONFIG_WPS */
4716 DBusMessageIter iter_dict, variant_iter;
8e2c5f1a 4717 int wps_support = 0;
caff3992
SN
4718 const char *type = "";
4719
4720 res = get_bss_helper(args, error, __func__);
4721 if (!res)
4722 return FALSE;
4723
4724 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
e3c4f0b5
JM
4725 "a{sv}", &variant_iter) ||
4726 !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
caff3992
SN
4727 goto nomem;
4728
4729#ifdef CONFIG_WPS
4730 wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
4731 if (wps_ie) {
8e2c5f1a 4732 wps_support = 1;
caff3992
SN
4733 if (wps_is_selected_pbc_registrar(wps_ie))
4734 type = "pbc";
4735 else if (wps_is_selected_pin_registrar(wps_ie))
4736 type = "pin";
c66f2349
SM
4737
4738 wpabuf_free(wps_ie);
caff3992
SN
4739 }
4740#endif /* CONFIG_WPS */
4741
8e2c5f1a 4742 if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) ||
e3c4f0b5
JM
4743 !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
4744 !dbus_message_iter_close_container(iter, &variant_iter))
caff3992
SN
4745 goto nomem;
4746
4747 return TRUE;
4748
4749nomem:
4750 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4751 return FALSE;
4752}
4753
4754
58605c6e 4755/**
7899e2f4 4756 * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
6aeeb6fa
DW
4757 * @iter: Pointer to incoming dbus message iter
4758 * @error: Location to store error on failure
4759 * @user_data: Function specific data
4760 * Returns: TRUE on success, FALSE on failure
58605c6e 4761 *
7899e2f4 4762 * Getter for "IEs" property.
58605c6e 4763 */
1aa0fb77
DW
4764dbus_bool_t wpas_dbus_getter_bss_ies(
4765 const struct wpa_dbus_property_desc *property_desc,
4766 DBusMessageIter *iter, DBusError *error, void *user_data)
58605c6e 4767{
6aeeb6fa
DW
4768 struct bss_handler_args *args = user_data;
4769 struct wpa_bss *res;
58605c6e 4770
6aeeb6fa
DW
4771 res = get_bss_helper(args, error, __func__);
4772 if (!res)
4773 return FALSE;
58605c6e 4774
6aeeb6fa
DW
4775 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4776 res + 1, res->ie_len,
4777 error);
8fc2fb56
WS
4778}
4779
4780
3bd3257a
DW
4781/**
4782 * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
4783 * @iter: Pointer to incoming dbus message iter
4784 * @error: Location to store error on failure
4785 * @user_data: Function specific data
4786 * Returns: TRUE on success, FALSE on failure
4787 *
4788 * Getter for BSS age
4789 */
1aa0fb77
DW
4790dbus_bool_t wpas_dbus_getter_bss_age(
4791 const struct wpa_dbus_property_desc *property_desc,
4792 DBusMessageIter *iter, DBusError *error, void *user_data)
3bd3257a
DW
4793{
4794 struct bss_handler_args *args = user_data;
4795 struct wpa_bss *res;
4796 struct os_reltime now, diff = { 0, 0 };
4797 u32 age;
4798
4799 res = get_bss_helper(args, error, __func__);
4800 if (!res)
4801 return FALSE;
4802
4803 os_get_reltime(&now);
4804 os_reltime_sub(&now, &res->last_update, &diff);
4805 age = diff.sec > 0 ? diff.sec : 0;
4806 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
4807 error);
4808}
4809
4810
8fc2fb56
WS
4811/**
4812 * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
6aeeb6fa
DW
4813 * @iter: Pointer to incoming dbus message iter
4814 * @error: Location to store error on failure
4815 * @user_data: Function specific data
4816 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
4817 *
4818 * Getter for "enabled" property of a configured network.
4819 */
1aa0fb77
DW
4820dbus_bool_t wpas_dbus_getter_enabled(
4821 const struct wpa_dbus_property_desc *property_desc,
4822 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 4823{
6aeeb6fa 4824 struct network_handler_args *net = user_data;
8fc2fb56 4825 dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
6aeeb6fa
DW
4826
4827 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
4828 &enabled, error);
8fc2fb56
WS
4829}
4830
4831
4832/**
4833 * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
6aeeb6fa
DW
4834 * @iter: Pointer to incoming dbus message iter
4835 * @error: Location to store error on failure
4836 * @user_data: Function specific data
4837 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
4838 *
4839 * Setter for "Enabled" property of a configured network.
4840 */
1aa0fb77
DW
4841dbus_bool_t wpas_dbus_setter_enabled(
4842 const struct wpa_dbus_property_desc *property_desc,
4843 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 4844{
6aeeb6fa 4845 struct network_handler_args *net = user_data;
8fc2fb56
WS
4846 struct wpa_supplicant *wpa_s;
4847 struct wpa_ssid *ssid;
8fc2fb56
WS
4848 dbus_bool_t enable;
4849
6aeeb6fa
DW
4850 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
4851 &enable))
4852 return FALSE;
8fc2fb56
WS
4853
4854 wpa_s = net->wpa_s;
4855 ssid = net->ssid;
4856
5228401c 4857 if (enable)
8fc2fb56 4858 wpa_supplicant_enable_network(wpa_s, ssid);
5228401c 4859 else
8fc2fb56 4860 wpa_supplicant_disable_network(wpa_s, ssid);
8fc2fb56 4861
6aeeb6fa 4862 return TRUE;
8fc2fb56
WS
4863}
4864
4865
4866/**
4867 * wpas_dbus_getter_network_properties - Get options for a configured network
6aeeb6fa
DW
4868 * @iter: Pointer to incoming dbus message iter
4869 * @error: Location to store error on failure
4870 * @user_data: Function specific data
4871 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
4872 *
4873 * Getter for "Properties" property of a configured network.
4874 */
1aa0fb77
DW
4875dbus_bool_t wpas_dbus_getter_network_properties(
4876 const struct wpa_dbus_property_desc *property_desc,
4877 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 4878{
6aeeb6fa
DW
4879 struct network_handler_args *net = user_data;
4880 DBusMessageIter variant_iter, dict_iter;
8fc2fb56 4881 char **iterator;
d1c8ac88 4882 char **props = wpa_config_get_all(net->ssid, 1);
6aeeb6fa 4883 dbus_bool_t success = FALSE;
8fc2fb56 4884
6aeeb6fa
DW
4885 if (!props) {
4886 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4887 return FALSE;
8fc2fb56
WS
4888 }
4889
6aeeb6fa
DW
4890 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
4891 &variant_iter) ||
c2b8c674 4892 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
6aeeb6fa 4893 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
8fc2fb56
WS
4894 goto out;
4895 }
4896
4897 iterator = props;
4898 while (*iterator) {
4899 if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
5228401c 4900 *(iterator + 1))) {
6aeeb6fa
DW
4901 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4902 "no memory");
8fc2fb56
WS
4903 goto out;
4904 }
4905 iterator += 2;
4906 }
4907
4908
c2b8c674 4909 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
6aeeb6fa
DW
4910 !dbus_message_iter_close_container(iter, &variant_iter)) {
4911 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
8fc2fb56
WS
4912 goto out;
4913 }
4914
6aeeb6fa
DW
4915 success = TRUE;
4916
8fc2fb56
WS
4917out:
4918 iterator = props;
4919 while (*iterator) {
4920 os_free(*iterator);
4921 iterator++;
4922 }
4923 os_free(props);
6aeeb6fa 4924 return success;
8fc2fb56
WS
4925}
4926
4927
4928/**
4929 * wpas_dbus_setter_network_properties - Set options for a configured network
6aeeb6fa
DW
4930 * @iter: Pointer to incoming dbus message iter
4931 * @error: Location to store error on failure
4932 * @user_data: Function specific data
4933 * Returns: TRUE on success, FALSE on failure
8fc2fb56
WS
4934 *
4935 * Setter for "Properties" property of a configured network.
4936 */
1aa0fb77
DW
4937dbus_bool_t wpas_dbus_setter_network_properties(
4938 const struct wpa_dbus_property_desc *property_desc,
4939 DBusMessageIter *iter, DBusError *error, void *user_data)
8fc2fb56 4940{
6aeeb6fa 4941 struct network_handler_args *net = user_data;
8fc2fb56 4942 struct wpa_ssid *ssid = net->ssid;
6aeeb6fa 4943 DBusMessageIter variant_iter;
8fc2fb56 4944
6aeeb6fa
DW
4945 dbus_message_iter_recurse(iter, &variant_iter);
4946 return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
8fc2fb56 4947}
2d43d37f
JB
4948
4949
4950#ifdef CONFIG_AP
4951
4952DBusMessage * wpas_dbus_handler_subscribe_preq(
4953 DBusMessage *message, struct wpa_supplicant *wpa_s)
4954{
4955 struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4956 char *name;
4957
4958 if (wpa_s->preq_notify_peer != NULL) {
4959 if (os_strcmp(dbus_message_get_sender(message),
4960 wpa_s->preq_notify_peer) == 0)
4961 return NULL;
4962
4963 return dbus_message_new_error(message,
4964 WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
4965 "Another application is already subscribed");
4966 }
4967
4968 name = os_strdup(dbus_message_get_sender(message));
4969 if (!name)
a0caebf3 4970 return wpas_dbus_error_no_memory(message);
2d43d37f
JB
4971
4972 wpa_s->preq_notify_peer = name;
4973
4974 /* Subscribe to clean up if application closes socket */
4975 wpas_dbus_subscribe_noc(priv);
4976
4977 /*
4978 * Double-check it's still alive to make sure that we didn't
4979 * miss the NameOwnerChanged signal, e.g. while strdup'ing.
4980 */
4981 if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
4982 /*
4983 * Application no longer exists, clean up.
4984 * The return value is irrelevant now.
4985 *
4986 * Need to check if the NameOwnerChanged handling
4987 * already cleaned up because we have processed
4988 * DBus messages while checking if the name still
4989 * has an owner.
4990 */
4991 if (!wpa_s->preq_notify_peer)
4992 return NULL;
4993 os_free(wpa_s->preq_notify_peer);
4994 wpa_s->preq_notify_peer = NULL;
4995 wpas_dbus_unsubscribe_noc(priv);
4996 }
4997
4998 return NULL;
4999}
5000
5001
5002DBusMessage * wpas_dbus_handler_unsubscribe_preq(
5003 DBusMessage *message, struct wpa_supplicant *wpa_s)
5004{
5005 struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5006
5007 if (!wpa_s->preq_notify_peer)
5008 return dbus_message_new_error(message,
5009 WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
5010 "Not subscribed");
5011
5012 if (os_strcmp(wpa_s->preq_notify_peer,
5013 dbus_message_get_sender(message)))
5014 return dbus_message_new_error(message,
5015 WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
5016 "Can't unsubscribe others");
5017
5018 os_free(wpa_s->preq_notify_peer);
5019 wpa_s->preq_notify_peer = NULL;
5020 wpas_dbus_unsubscribe_noc(priv);
5021 return NULL;
5022}
5023
5024
5025void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
5026 const u8 *addr, const u8 *dst, const u8 *bssid,
5027 const u8 *ie, size_t ie_len, u32 ssi_signal)
5028{
5029 DBusMessage *msg;
5030 DBusMessageIter iter, dict_iter;
5031 struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5032
5033 /* Do nothing if the control interface is not turned on */
8a78e227 5034 if (priv == NULL || !wpa_s->dbus_new_path)
2d43d37f
JB
5035 return;
5036
5037 if (wpa_s->preq_notify_peer == NULL)
5038 return;
5039
5040 msg = dbus_message_new_signal(wpa_s->dbus_new_path,
5041 WPAS_DBUS_NEW_IFACE_INTERFACE,
5042 "ProbeRequest");
5043 if (msg == NULL)
5044 return;
5045
5046 dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
5047
5048 dbus_message_iter_init_append(msg, &iter);
5049
e3c4f0b5
JM
5050 if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
5051 (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
5052 (const char *) addr,
5053 ETH_ALEN)) ||
5054 (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
5055 (const char *) dst,
5056 ETH_ALEN)) ||
5057 (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
5058 (const char *) bssid,
5059 ETH_ALEN)) ||
5060 (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
5061 (const char *) ie,
5062 ie_len)) ||
5063 (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
5064 ssi_signal)) ||
5065 !wpa_dbus_dict_close_write(&iter, &dict_iter))
2d43d37f
JB
5066 goto fail;
5067
5068 dbus_connection_send(priv->con, msg, NULL);
5069 goto out;
5070fail:
5071 wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
5072out:
5073 dbus_message_unref(msg);
5074}
5075
5076#endif /* CONFIG_AP */
af041f99
AA
5077
5078
5079DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
5080 struct wpa_supplicant *wpa_s)
5081{
5082 u8 *ielems;
5083 int len;
5084 struct ieee802_11_elems elems;
5085 dbus_int32_t frame_id;
5086 DBusMessageIter iter, array;
5087
5088 dbus_message_iter_init(message, &iter);
5089 dbus_message_iter_get_basic(&iter, &frame_id);
5090 if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5091 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5092 "Invalid ID");
5093 }
5094
5095 dbus_message_iter_next(&iter);
5096 dbus_message_iter_recurse(&iter, &array);
5097 dbus_message_iter_get_fixed_array(&array, &ielems, &len);
5098 if (!ielems || len == 0) {
5099 return dbus_message_new_error(
5100 message, DBUS_ERROR_INVALID_ARGS, "Invalid value");
5101 }
5102
5103 if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
5104 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5105 "Parse error");
5106 }
5107
5108 wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5109 if (!wpa_s->vendor_elem[frame_id]) {
5110 wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len);
5111 wpas_vendor_elem_update(wpa_s);
5112 return NULL;
5113 }
5114
5115 if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) {
5116 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5117 "Resize error");
5118 }
5119
5120 wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len);
5121 wpas_vendor_elem_update(wpa_s);
5122 return NULL;
5123}
5124
5125
5126DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
5127 struct wpa_supplicant *wpa_s)
5128{
5129 DBusMessage *reply;
5130 DBusMessageIter iter, array_iter;
5131 dbus_int32_t frame_id;
5132 const u8 *elem;
5133 size_t elem_len;
5134
5135 dbus_message_iter_init(message, &iter);
5136 dbus_message_iter_get_basic(&iter, &frame_id);
5137
5138 if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5139 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5140 "Invalid ID");
5141 }
5142
5143 wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5144 if (!wpa_s->vendor_elem[frame_id]) {
5145 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5146 "ID value does not exist");
5147 }
5148
5149 reply = dbus_message_new_method_return(message);
5150 if (!reply)
5151 return wpas_dbus_error_no_memory(message);
5152
5153 dbus_message_iter_init_append(reply, &iter);
5154
5155 elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]);
5156 elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
5157
5158 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
5159 DBUS_TYPE_BYTE_AS_STRING,
5160 &array_iter) ||
5161 !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
5162 &elem, elem_len) ||
5163 !dbus_message_iter_close_container(&iter, &array_iter)) {
5164 dbus_message_unref(reply);
5165 reply = wpas_dbus_error_no_memory(message);
5166 }
5167
5168 return reply;
5169}
5170
5171
5172DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message,
5173 struct wpa_supplicant *wpa_s)
5174{
5175 u8 *ielems;
5176 int len;
5177 struct ieee802_11_elems elems;
5178 DBusMessageIter iter, array;
5179 dbus_int32_t frame_id;
5180
5181 dbus_message_iter_init(message, &iter);
5182 dbus_message_iter_get_basic(&iter, &frame_id);
5183 if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5184 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5185 "Invalid ID");
5186 }
5187
5188 dbus_message_iter_next(&iter);
5189 dbus_message_iter_recurse(&iter, &array);
5190 dbus_message_iter_get_fixed_array(&array, &ielems, &len);
5191 if (!ielems || len == 0) {
5192 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5193 "Invalid value");
5194 }
5195
5196 wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5197
5198 if (len == 1 && *ielems == '*') {
5199 wpabuf_free(wpa_s->vendor_elem[frame_id]);
5200 wpa_s->vendor_elem[frame_id] = NULL;
5201 wpas_vendor_elem_update(wpa_s);
5202 return NULL;
5203 }
5204
5205 if (!wpa_s->vendor_elem[frame_id]) {
5206 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5207 "ID value does not exist");
5208 }
5209
5210 if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
5211 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5212 "Parse error");
5213 }
5214
5215 if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0)
5216 return NULL;
5217
5218 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5219 "Not found");
5220}
190f6f11
SB
5221
5222
5223#ifdef CONFIG_MESH
cdf25014 5224
190f6f11
SB
5225/**
5226 * wpas_dbus_getter_mesh_peers - Get connected mesh peers
5227 * @iter: Pointer to incoming dbus message iter
5228 * @error: Location to store error on failure
5229 * @user_data: Function specific data
5230 * Returns: TRUE on success, FALSE on failure
5231 *
5232 * Getter for "MeshPeers" property.
5233 */
5234dbus_bool_t wpas_dbus_getter_mesh_peers(
5235 const struct wpa_dbus_property_desc *property_desc,
5236 DBusMessageIter *iter, DBusError *error, void *user_data)
5237{
5238 struct wpa_supplicant *wpa_s = user_data;
5239 struct hostapd_data *hapd;
5240 struct sta_info *sta;
5241 DBusMessageIter variant_iter, array_iter;
5242 int i;
5243 DBusMessageIter inner_array_iter;
5244
5245 if (!wpa_s->ifmsh)
5246 return FALSE;
5247 hapd = wpa_s->ifmsh->bss[0];
5248
5249 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
5250 DBUS_TYPE_ARRAY_AS_STRING
5251 DBUS_TYPE_ARRAY_AS_STRING
5252 DBUS_TYPE_BYTE_AS_STRING,
5253 &variant_iter) ||
5254 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
5255 DBUS_TYPE_ARRAY_AS_STRING
5256 DBUS_TYPE_BYTE_AS_STRING,
5257 &array_iter))
5258 return FALSE;
5259
5260 for (sta = hapd->sta_list; sta; sta = sta->next) {
5261 if (!dbus_message_iter_open_container(
5262 &array_iter, DBUS_TYPE_ARRAY,
5263 DBUS_TYPE_BYTE_AS_STRING,
5264 &inner_array_iter))
5265 return FALSE;
5266
5267 for (i = 0; i < ETH_ALEN; i++) {
5268 if (!dbus_message_iter_append_basic(&inner_array_iter,
5269 DBUS_TYPE_BYTE,
5270 &(sta->addr[i])))
5271 return FALSE;
5272 }
5273
5274 if (!dbus_message_iter_close_container(
5275 &array_iter, &inner_array_iter))
5276 return FALSE;
5277 }
5278
5279 if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
5280 !dbus_message_iter_close_container(iter, &variant_iter))
5281 return FALSE;
5282
5283 return TRUE;
5284}
cdf25014
SB
5285
5286
5287/**
5288 * wpas_dbus_getter_mesh_group - Get mesh group
5289 * @iter: Pointer to incoming dbus message iter
5290 * @error: Location to store error on failure
5291 * @user_data: Function specific data
5292 * Returns: TRUE on success, FALSE on failure
5293 *
5294 * Getter for "MeshGroup" property.
5295 */
5296dbus_bool_t wpas_dbus_getter_mesh_group(
5297 const struct wpa_dbus_property_desc *property_desc,
5298 DBusMessageIter *iter, DBusError *error, void *user_data)
5299{
5300 struct wpa_supplicant *wpa_s = user_data;
5301 struct wpa_ssid *ssid = wpa_s->current_ssid;
5302
5303 if (!wpa_s->ifmsh || !ssid)
5304 return FALSE;
5305
5306 if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
5307 (char *) ssid->ssid,
5308 ssid->ssid_len, error)) {
5309 dbus_set_error(error, DBUS_ERROR_FAILED,
5310 "%s: error constructing reply", __func__);
5311 return FALSE;
5312 }
5313
5314 return TRUE;
5315}
5316
190f6f11 5317#endif /* CONFIG_MESH */