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