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