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