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