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