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