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