dbus: Add generic properties getter and setter
[libeap.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, Witold Sowa <witold.sowa@gmail.com>
5  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * Alternatively, this software may be distributed under the terms of BSD
12  * license.
13  *
14  * See README and COPYING for more details.
15  */
16
17 #include "includes.h"
18
19 #include "common.h"
20 #include "common/ieee802_11_defs.h"
21 #include "eap_peer/eap_methods.h"
22 #include "eapol_supp/eapol_supp_sm.h"
23 #include "../config.h"
24 #include "../wpa_supplicant_i.h"
25 #include "../driver_i.h"
26 #include "../notify.h"
27 #include "../wpas_glue.h"
28 #include "../bss.h"
29 #include "dbus_new_helpers.h"
30 #include "dbus_new.h"
31 #include "dbus_new_handlers.h"
32 #include "dbus_dict_helpers.h"
33
34 extern int wpa_debug_level;
35 extern int wpa_debug_show_keys;
36 extern int wpa_debug_timestamp;
37
38
39 /**
40  * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
41  * @path: The dbus object path
42  * @network: (out) the configured network this object path refers to, if any
43  * @bssid: (out) the scanned bssid this object path refers to, if any
44  * Returns: The object path of the network interface this path refers to
45  *
46  * For a given object path, decomposes the object path into object id, network,
47  * and BSSID parts, if those parts exist.
48  */
49 static char * wpas_dbus_new_decompose_object_path(const char *path,
50                                                   char **network,
51                                                   char **bssid)
52 {
53         const unsigned int dev_path_prefix_len =
54                 strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
55         char *obj_path_only;
56         char *next_sep;
57
58         /* Be a bit paranoid about path */
59         if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
60                                 dev_path_prefix_len))
61                 return NULL;
62
63         /* Ensure there's something at the end of the path */
64         if ((path + dev_path_prefix_len)[0] == '\0')
65                 return NULL;
66
67         obj_path_only = os_strdup(path);
68         if (obj_path_only == NULL)
69                 return NULL;
70
71         next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
72         if (next_sep != NULL) {
73                 const char *net_part = os_strstr(
74                         next_sep, WPAS_DBUS_NEW_NETWORKS_PART "/");
75                 const char *bssid_part = os_strstr(
76                         next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
77
78                 if (network && net_part) {
79                         /* Deal with a request for a configured network */
80                         const char *net_name = net_part +
81                                 os_strlen(WPAS_DBUS_NEW_NETWORKS_PART "/");
82                         *network = NULL;
83                         if (os_strlen(net_name))
84                                 *network = os_strdup(net_name);
85                 } else if (bssid && bssid_part) {
86                         /* Deal with a request for a scanned BSSID */
87                         const char *bssid_name = bssid_part +
88                                 os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
89                         if (strlen(bssid_name))
90                                 *bssid = os_strdup(bssid_name);
91                         else
92                                 *bssid = NULL;
93                 }
94
95                 /* Cut off interface object path before "/" */
96                 *next_sep = '\0';
97         }
98
99         return obj_path_only;
100 }
101
102
103 /**
104  * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
105  * @message: Pointer to incoming dbus message this error refers to
106  * @arg: Optional string appended to error message
107  * Returns: a dbus error message
108  *
109  * Convenience function to create and return an UnknownError
110  */
111 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
112                                             const char *arg)
113 {
114         return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
115                                       arg);
116 }
117
118
119 /**
120  * wpas_dbus_error_iface_unknown - Return a new invalid interface error message
121  * @message: Pointer to incoming dbus message this error refers to
122  * Returns: A dbus error message
123  *
124  * Convenience function to create and return an invalid interface error
125  */
126 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
127 {
128         return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
129                                       "wpa_supplicant knows nothing about "
130                                       "this interface.");
131 }
132
133
134 /**
135  * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
136  * @message: Pointer to incoming dbus message this error refers to
137  * Returns: a dbus error message
138  *
139  * Convenience function to create and return an invalid network error
140  */
141 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
142 {
143         return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
144                                       "There is no such a network in this "
145                                       "interface.");
146 }
147
148
149 /**
150  * wpas_dbus_error_invald_args - Return a new InvalidArgs error message
151  * @message: Pointer to incoming dbus message this error refers to
152  * Returns: a dbus error message
153  *
154  * Convenience function to create and return an invalid options error
155  */
156 DBusMessage * wpas_dbus_error_invald_args(DBusMessage *message,
157                                           const char *arg)
158 {
159         DBusMessage *reply;
160
161         reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
162                                        "Did not receive correct message "
163                                        "arguments.");
164         if (arg != NULL)
165                 dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
166                                          DBUS_TYPE_INVALID);
167
168         return reply;
169 }
170
171
172 static const char *dont_quote[] = {
173         "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
174         "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
175         "bssid", NULL
176 };
177
178 static dbus_bool_t should_quote_opt(const char *key)
179 {
180         int i = 0;
181         while (dont_quote[i] != NULL) {
182                 if (os_strcmp(key, dont_quote[i]) == 0)
183                         return FALSE;
184                 i++;
185         }
186         return TRUE;
187 }
188
189 /**
190  * get_iface_by_dbus_path - Get a new network interface
191  * @global: Pointer to global data from wpa_supplicant_init()
192  * @path: Pointer to a dbus object path representing an interface
193  * Returns: Pointer to the interface or %NULL if not found
194  */
195 static struct wpa_supplicant * get_iface_by_dbus_path(
196         struct wpa_global *global, const char *path)
197 {
198         struct wpa_supplicant *wpa_s;
199
200         for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
201                 if (os_strcmp(wpa_s->dbus_new_path, path) == 0)
202                         return wpa_s;
203         }
204         return NULL;
205 }
206
207
208 /**
209  * set_network_properties - Set properties of a configured network
210  * @message: Pointer to incoming dbus message
211  * @ssid: wpa_ssid structure for a configured network
212  * @iter: DBus message iterator containing dictionary of network
213  * properties to set.
214  * Returns: NULL when succeed or DBus error on failure
215  *
216  * Sets network configuration with parameters given id DBus dictionary
217  */
218 static DBusMessage * set_network_properties(DBusMessage *message,
219                                             struct wpa_ssid *ssid,
220                                             DBusMessageIter *iter)
221 {
222
223         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
224         DBusMessage *reply = NULL;
225         DBusMessageIter iter_dict;
226
227         if (!wpa_dbus_dict_open_read(iter, &iter_dict))
228                 return wpas_dbus_error_invald_args(message, NULL);
229
230         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
231                 char *value = NULL;
232                 size_t size = 50;
233                 int ret;
234                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
235                         reply = wpas_dbus_error_invald_args(message, NULL);
236                         break;
237                 }
238                 if (entry.type == DBUS_TYPE_ARRAY &&
239                     entry.array_type == DBUS_TYPE_BYTE) {
240                         if (entry.array_len <= 0)
241                                 goto error;
242
243                         size = entry.array_len * 2 + 1;
244                         value = os_zalloc(size);
245                         if (value == NULL)
246                                 goto error;
247
248                         ret = wpa_snprintf_hex(value, size,
249                                                (u8 *) entry.bytearray_value,
250                                                entry.array_len);
251                         if (ret <= 0)
252                                 goto error;
253                 } else if (entry.type == DBUS_TYPE_STRING) {
254                         if (should_quote_opt(entry.key)) {
255                                 size = os_strlen(entry.str_value);
256                                 if (size <= 0)
257                                         goto error;
258
259                                 size += 3;
260                                 value = os_zalloc(size);
261                                 if (value == NULL)
262                                         goto error;
263
264                                 ret = os_snprintf(value, size, "\"%s\"",
265                                                   entry.str_value);
266                                 if (ret < 0 || (size_t) ret != (size - 1))
267                                         goto error;
268                         } else {
269                                 value = os_strdup(entry.str_value);
270                                 if (value == NULL)
271                                         goto error;
272                         }
273                 } else if (entry.type == DBUS_TYPE_UINT32) {
274                         value = os_zalloc(size);
275                         if (value == NULL)
276                                 goto error;
277
278                         ret = os_snprintf(value, size, "%u",
279                                           entry.uint32_value);
280                         if (ret <= 0)
281                                 goto error;
282                 } else if (entry.type == DBUS_TYPE_INT32) {
283                         value = os_zalloc(size);
284                         if (value == NULL)
285                                 goto error;
286
287                         ret = os_snprintf(value, size, "%d",
288                                           entry.int32_value);
289                         if (ret <= 0)
290                                 goto error;
291                 } else
292                         goto error;
293
294                 if (wpa_config_set(ssid, entry.key, value, 0) < 0)
295                         goto error;
296
297                 if ((os_strcmp(entry.key, "psk") == 0 &&
298                      value[0] == '"' && ssid->ssid_len) ||
299                     (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
300                         wpa_config_update_psk(ssid);
301
302                 os_free(value);
303                 wpa_dbus_dict_entry_clear(&entry);
304                 continue;
305
306         error:
307                 os_free(value);
308                 reply = wpas_dbus_error_invald_args(message, entry.key);
309                 wpa_dbus_dict_entry_clear(&entry);
310                 break;
311         }
312
313         return reply;
314 }
315
316
317 static const char * _get_dbus_type_as_string(const int type)
318 {
319         switch(type) {
320         case DBUS_TYPE_BYTE:
321                 return DBUS_TYPE_BYTE_AS_STRING;
322         case DBUS_TYPE_BOOLEAN:
323                 return DBUS_TYPE_BOOLEAN_AS_STRING;
324         case DBUS_TYPE_INT16:
325                 return DBUS_TYPE_INT16_AS_STRING;
326         case DBUS_TYPE_UINT16:
327                 return DBUS_TYPE_UINT16_AS_STRING;
328         case DBUS_TYPE_INT32:
329                 return DBUS_TYPE_INT32_AS_STRING;
330         case DBUS_TYPE_UINT32:
331                 return DBUS_TYPE_UINT32_AS_STRING;
332         case DBUS_TYPE_INT64:
333                 return DBUS_TYPE_INT64_AS_STRING;
334         case DBUS_TYPE_UINT64:
335                 return DBUS_TYPE_UINT64_AS_STRING;
336         case DBUS_TYPE_DOUBLE:
337                 return DBUS_TYPE_DOUBLE_AS_STRING;
338         case DBUS_TYPE_STRING:
339                 return DBUS_TYPE_STRING_AS_STRING;
340         case DBUS_TYPE_OBJECT_PATH:
341                 return DBUS_TYPE_OBJECT_PATH_AS_STRING;
342         default:
343                 return NULL;
344         }
345 }
346
347
348 /**
349  * wpas_dbus_simple_property_getter - Get basic type property
350  * @message: Pointer to incoming dbus message
351  * @type: DBus type of property (must be basic type)
352  * @val: pointer to place holding property value
353  * Returns: The DBus message containing response for Properties.Get call
354  * or DBus error message if error occurred.
355  *
356  * Generic getter for basic type properties. Type is required to be basic.
357  */
358 DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
359                                                const int type, const void *val)
360 {
361         DBusMessage *reply = NULL;
362         DBusMessageIter iter, variant_iter;
363
364         if (!dbus_type_is_basic(type)) {
365                 wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
366                            " given type is not basic");
367                 return wpas_dbus_error_unknown_error(message, NULL);
368         }
369
370         if (message == NULL)
371                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
372         else
373                 reply = dbus_message_new_method_return(message);
374
375         if (reply != NULL) {
376                 dbus_message_iter_init_append(reply, &iter);
377                 if (!dbus_message_iter_open_container(
378                             &iter, DBUS_TYPE_VARIANT,
379                             _get_dbus_type_as_string(type), &variant_iter) ||
380                     !dbus_message_iter_append_basic(&variant_iter, type,
381                                                     val) ||
382                     !dbus_message_iter_close_container(&iter, &variant_iter)) {
383                         wpa_printf(MSG_ERROR, "dbus: "
384                                    "wpas_dbus_simple_property_getter: out of "
385                                    "memory to put property value into "
386                                    "message");
387                         dbus_message_unref(reply);
388                         reply = dbus_message_new_error(message,
389                                                        DBUS_ERROR_NO_MEMORY,
390                                                        NULL);
391                 }
392         } else {
393                 wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
394                            " out of memory to return property value");
395                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
396                                                NULL);
397         }
398
399         return reply;
400 }
401
402
403 /**
404  * wpas_dbus_simple_property_setter - Set basic type property
405  * @message: Pointer to incoming dbus message
406  * @type: DBus type of property (must be basic type)
407  * @val: pointer to place where value being set will be stored
408  * Returns: NULL or DBus error message if error occurred.
409  *
410  * Generic setter for basic type properties. Type is required to be basic.
411  */
412 DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message,
413                                                const int type, void *val)
414 {
415         DBusMessageIter iter, variant_iter;
416
417         if (!dbus_type_is_basic(type)) {
418                 wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
419                            " given type is not basic");
420                 return wpas_dbus_error_unknown_error(message, NULL);
421         }
422
423         if (!dbus_message_iter_init(message, &iter)) {
424                 wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
425                            " out of memory to return scanning state");
426                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
427                                               NULL);
428         }
429
430         /* omit first and second argument and get value from third */
431         dbus_message_iter_next(&iter);
432         dbus_message_iter_next(&iter);
433         dbus_message_iter_recurse(&iter, &variant_iter);
434
435         if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
436                 return wpas_dbus_error_invald_args(message,
437                                                    "wrong property type");
438         }
439         dbus_message_iter_get_basic(&variant_iter, val);
440
441         return NULL;
442 }
443
444
445 /**
446  * wpas_dbus_simple_array_property_getter - Get array type property
447  * @message: Pointer to incoming dbus message
448  * @type: DBus type of property array elements (must be basic type)
449  * @array: pointer to array of elements to put into response message
450  * @array_len: length of above array
451  * Returns: The DBus message containing response for Properties.Get call
452  * or DBus error message if error occurred.
453  *
454  * Generic getter for array type properties. Array elements type is
455  * required to be basic.
456  */
457 DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
458                                                      const int type,
459                                                      const void *array,
460                                                      size_t array_len)
461 {
462         DBusMessage *reply = NULL;
463         DBusMessageIter iter, variant_iter, array_iter;
464         char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
465         const char *sub_type_str;
466         size_t element_size, i;
467
468         if (!dbus_type_is_basic(type)) {
469                 wpa_printf(MSG_ERROR, "dbus: "
470                            "wpas_dbus_simple_array_property_getter: given "
471                            "type is not basic");
472                 return wpas_dbus_error_unknown_error(message, NULL);
473         }
474
475         sub_type_str = _get_dbus_type_as_string(type);
476         type_str[1] = sub_type_str[0];
477
478         if (message == NULL)
479                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
480         else
481                 reply = dbus_message_new_method_return(message);
482         if (reply == NULL) {
483                 wpa_printf(MSG_ERROR, "dbus: "
484                            "wpas_dbus_simple_array_property_getter: out of "
485                            "memory to create return message");
486                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
487                                               NULL);
488         }
489
490         dbus_message_iter_init_append(reply, &iter);
491
492         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
493                                               type_str, &variant_iter) ||
494             !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
495                                               sub_type_str, &array_iter)) {
496                 wpa_printf(MSG_ERROR, "dbus: "
497                            "wpas_dbus_simple_array_property_getter: out of "
498                            "memory to open container");
499                 dbus_message_unref(reply);
500                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
501                                               NULL);
502         }
503
504         switch(type) {
505         case DBUS_TYPE_BYTE:
506         case DBUS_TYPE_BOOLEAN:
507                 element_size = 1;
508                 break;
509         case DBUS_TYPE_INT16:
510         case DBUS_TYPE_UINT16:
511                 element_size = sizeof(uint16_t);
512                 break;
513         case DBUS_TYPE_INT32:
514         case DBUS_TYPE_UINT32:
515                 element_size = sizeof(uint32_t);
516                 break;
517         case DBUS_TYPE_INT64:
518         case DBUS_TYPE_UINT64:
519                 element_size = sizeof(uint64_t);
520                 break;
521         case DBUS_TYPE_DOUBLE:
522                 element_size = sizeof(double);
523                 break;
524         case DBUS_TYPE_STRING:
525         case DBUS_TYPE_OBJECT_PATH:
526                 element_size = sizeof(char *);
527                 break;
528         default:
529                 wpa_printf(MSG_ERROR, "dbus: "
530                            "wpas_dbus_simple_array_property_getter: "
531                            "fatal: unknown element type");
532                 element_size = 1;
533                 break;
534         }
535
536         for (i = 0; i < array_len; i++) {
537                 dbus_message_iter_append_basic(&array_iter, type,
538                                                array + i * element_size);
539         }
540
541         if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
542             !dbus_message_iter_close_container(&iter, &variant_iter)) {
543                 wpa_printf(MSG_ERROR, "dbus: "
544                            "wpas_dbus_simple_array_property_getter: out of "
545                            "memory to close container");
546                 dbus_message_unref(reply);
547                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
548                                               NULL);
549         }
550
551         return reply;
552 }
553
554
555 /**
556  * wpas_dbus_handler_create_interface - Request registration of a network iface
557  * @message: Pointer to incoming dbus message
558  * @global: %wpa_supplicant global data structure
559  * Returns: The object path of the new interface object,
560  *          or a dbus error message with more information
561  *
562  * Handler function for "CreateInterface" method call. Handles requests
563  * by dbus clients to register a network interface that wpa_supplicant
564  * will manage.
565  */
566 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
567                                                  struct wpa_global *global)
568 {
569         DBusMessageIter iter_dict;
570         DBusMessage *reply = NULL;
571         DBusMessageIter iter;
572         struct wpa_dbus_dict_entry entry;
573         char *driver = NULL;
574         char *ifname = NULL;
575         char *bridge_ifname = NULL;
576
577         dbus_message_iter_init(message, &iter);
578
579         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
580                 goto error;
581         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
582                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
583                         goto error;
584                 if (!strcmp(entry.key, "Driver") &&
585                     (entry.type == DBUS_TYPE_STRING)) {
586                         driver = os_strdup(entry.str_value);
587                         wpa_dbus_dict_entry_clear(&entry);
588                         if (driver == NULL)
589                                 goto error;
590                 } else if (!strcmp(entry.key, "Ifname") &&
591                            (entry.type == DBUS_TYPE_STRING)) {
592                         ifname = os_strdup(entry.str_value);
593                         wpa_dbus_dict_entry_clear(&entry);
594                         if (ifname == NULL)
595                                 goto error;
596                 } else if (!strcmp(entry.key, "BridgeIfname") &&
597                            (entry.type == DBUS_TYPE_STRING)) {
598                         bridge_ifname = os_strdup(entry.str_value);
599                         wpa_dbus_dict_entry_clear(&entry);
600                         if (bridge_ifname == NULL)
601                                 goto error;
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(message,
617                                                WPAS_DBUS_ERROR_IFACE_EXISTS,
618                                                "wpa_supplicant already "
619                                                "controls this interface.");
620         } else {
621                 struct wpa_supplicant *wpa_s;
622                 struct wpa_interface iface;
623                 os_memset(&iface, 0, sizeof(iface));
624                 iface.driver = driver;
625                 iface.ifname = ifname;
626                 iface.bridge_ifname = bridge_ifname;
627                 /* Otherwise, have wpa_supplicant attach to it. */
628                 if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
629                         const char *path = wpas_dbus_get_path(wpa_s);
630                         reply = dbus_message_new_method_return(message);
631                         dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
632                                                  &path, DBUS_TYPE_INVALID);
633                 } else {
634                         reply = wpas_dbus_error_unknown_error(
635                                 message, "wpa_supplicant couldn't grab this "
636                                 "interface.");
637                 }
638         }
639
640 out:
641         os_free(driver);
642         os_free(ifname);
643         os_free(bridge_ifname);
644         return reply;
645
646 error:
647         reply = wpas_dbus_error_invald_args(message, NULL);
648         goto out;
649 }
650
651
652 /**
653  * wpas_dbus_handler_remove_interface - Request deregistration of an interface
654  * @message: Pointer to incoming dbus message
655  * @global: wpa_supplicant global data structure
656  * Returns: a dbus message containing a UINT32 indicating success (1) or
657  *          failure (0), or returns a dbus error message with more information
658  *
659  * Handler function for "removeInterface" method call.  Handles requests
660  * by dbus clients to deregister a network interface that wpa_supplicant
661  * currently manages.
662  */
663 DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
664                                                  struct wpa_global *global)
665 {
666         struct wpa_supplicant *wpa_s;
667         char *path;
668         DBusMessage *reply = NULL;
669
670         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
671                               DBUS_TYPE_INVALID);
672
673         wpa_s = get_iface_by_dbus_path(global, path);
674         if (wpa_s == NULL)
675                 reply = wpas_dbus_error_iface_unknown(message);
676         else if (wpa_supplicant_remove_iface(global, wpa_s)) {
677                 reply = wpas_dbus_error_unknown_error(
678                         message, "wpa_supplicant couldn't remove this "
679                         "interface.");
680         }
681
682         return reply;
683 }
684
685
686 /**
687  * wpas_dbus_handler_get_interface - Get the object path for an interface name
688  * @message: Pointer to incoming dbus message
689  * @global: %wpa_supplicant global data structure
690  * Returns: The object path of the interface object,
691  *          or a dbus error message with more information
692  *
693  * Handler function for "getInterface" method call.
694  */
695 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
696                                               struct wpa_global *global)
697 {
698         DBusMessage *reply = NULL;
699         const char *ifname;
700         const char *path;
701         struct wpa_supplicant *wpa_s;
702
703         dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
704                               DBUS_TYPE_INVALID);
705
706         wpa_s = wpa_supplicant_get_iface(global, ifname);
707         if (wpa_s == NULL)
708                 return wpas_dbus_error_iface_unknown(message);
709
710         path = wpas_dbus_get_path(wpa_s);
711         if (path == NULL) {
712                 wpa_printf(MSG_ERROR, "wpas_dbus_handler_get_interface[dbus]: "
713                            "interface has no dbus object path set");
714                 return wpas_dbus_error_unknown_error(message, "path not set");
715         }
716
717         reply = dbus_message_new_method_return(message);
718         if (reply == NULL) {
719                 perror("wpas_dbus_handler_get_interface[dbus]: out of memory "
720                        "when creating reply");
721                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
722                                               NULL);
723         }
724         if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
725                                       DBUS_TYPE_INVALID)) {
726                 perror("wpas_dbus_handler_get_interface[dbus]: out of memory "
727                        "when appending argument to reply");
728                 dbus_message_unref(reply);
729                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
730                                               NULL);
731         }
732
733         return reply;
734 }
735
736
737 /**
738  * wpas_dbus_getter_debug_params - Get the debug params
739  * @message: Pointer to incoming dbus message
740  * @global: %wpa_supplicant global data structure
741  * Returns: DBus message with struct containing debug params.
742  *
743  * Getter for "DebugParams" property.
744  */
745 DBusMessage * wpas_dbus_getter_debug_params(DBusMessage *message,
746                                             struct wpa_global *global)
747 {
748         DBusMessage *reply = NULL;
749         DBusMessageIter iter, variant_iter, struct_iter;
750
751         if (message == NULL)
752                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
753         else
754                 reply = dbus_message_new_method_return(message);
755         if (!reply) {
756                 perror("wpas_dbus_getter_network_properties[dbus] out of "
757                        "memory when trying to initialize return message");
758                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
759                                                NULL);
760                 goto out;
761         }
762
763         dbus_message_iter_init_append(reply, &iter);
764
765         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
766                                               "(ibb)", &variant_iter)) {
767                 perror("wpas_dbus_getter_debug_params[dbus] out of memory "
768                        "when trying to open variant");
769                 dbus_message_unref(reply);
770                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
771                                                NULL);
772                 goto out;
773         }
774
775         if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_STRUCT,
776                                               NULL, &struct_iter)) {
777                 perror("wpas_dbus_getter_debug_params[dbus] out of memory "
778                        "when trying to open struct");
779                 dbus_message_unref(reply);
780                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
781                                                NULL);
782                 goto out;
783         }
784
785         if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_INT32,
786                                             &wpa_debug_level)) {
787                 perror("wpas_dbus_getter_debug_params[dbus] out of memory "
788                        "when trying to append value to struct");
789                 dbus_message_unref(reply);
790                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
791                                                NULL);
792                 goto out;
793         }
794
795         if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_BOOLEAN,
796                                             &wpa_debug_timestamp)) {
797                 perror("wpas_dbus_getter_debug_params[dbus] out of memory "
798                        "when trying to append value to struct");
799                 dbus_message_unref(reply);
800                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
801                                                NULL);
802                 goto out;
803         }
804
805         if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_BOOLEAN,
806                                             &wpa_debug_show_keys)) {
807                 perror("wpas_dbus_getter_debug_params[dbus] out of memory "
808                        "when trying to append value to struct");
809                 dbus_message_unref(reply);
810                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
811                                                NULL);
812                 goto out;
813         }
814
815         if (!dbus_message_iter_close_container(&variant_iter, &struct_iter)) {
816                 perror("wpas_dbus_getter_debug_params[dbus] out of memory "
817                        "when trying to close struct");
818                 dbus_message_unref(reply);
819                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
820                                                NULL);
821                 goto out;
822         }
823
824         if (!dbus_message_iter_close_container(&iter, &variant_iter)) {
825                 perror("wpas_dbus_getter_debug_params[dbus] out of memory "
826                        "when trying to close variant");
827                 dbus_message_unref(reply);
828                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
829                                                NULL);
830                 goto out;
831         }
832
833 out:
834         return reply;
835 }
836
837
838 /**
839  * wpas_dbus_setter_debugparams - Set the debug params
840  * @message: Pointer to incoming dbus message
841  * @global: %wpa_supplicant global data structure
842  * Returns: NULL indicating success or a dbus error message with more
843  * information
844  *
845  * Setter for "DebugParams" property.
846  */
847 DBusMessage * wpas_dbus_setter_debug_params(DBusMessage *message,
848                                             struct wpa_global *global)
849 {
850         DBusMessage *reply = NULL;
851         DBusMessageIter iter, variant_iter, struct_iter;
852         int debug_level;
853         dbus_bool_t debug_timestamp;
854         dbus_bool_t debug_show_keys;
855
856         if (!dbus_message_iter_init(message, &iter)) {
857                 perror("wpas_dbus_handler_add_blob[dbus] out of memory when "
858                        "trying to initialize message iterator");
859                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
860                                                NULL);
861                 goto out;
862         }
863         dbus_message_iter_next(&iter);
864         dbus_message_iter_next(&iter);
865
866         dbus_message_iter_recurse(&iter, &variant_iter);
867
868         if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRUCT)
869         {
870                 reply = wpas_dbus_error_invald_args(
871                         message, "Argument must by a structure");
872                 goto out;
873         }
874
875         dbus_message_iter_recurse(&variant_iter, &struct_iter);
876
877
878         if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_INT32) {
879                 reply = wpas_dbus_error_invald_args(
880                         message, "First struct argument must by an INT32");
881                 goto out;
882         }
883
884         dbus_message_iter_get_basic(&struct_iter, &debug_level);
885         if (!dbus_message_iter_next(&struct_iter)) {
886                 reply = wpas_dbus_error_invald_args(
887                         message, "Not enough elements in struct");
888                 goto out;
889         }
890
891         if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_BOOLEAN)
892         {
893                 reply = wpas_dbus_error_invald_args(
894                         message, "Second struct argument must by a boolean");
895                 goto out;
896         }
897         dbus_message_iter_get_basic(&struct_iter, &debug_timestamp);
898         if (!dbus_message_iter_next(&struct_iter)) {
899                 reply = wpas_dbus_error_invald_args(
900                         message, "Not enough elements in struct");
901                 goto out;
902         }
903
904         if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_BOOLEAN)
905         {
906                 reply = wpas_dbus_error_invald_args(
907                         message, "Third struct argument must by an boolean");
908                 goto out;
909         }
910         dbus_message_iter_get_basic(&struct_iter, &debug_show_keys);
911
912         if (wpa_supplicant_set_debug_params(global, debug_level,
913                                             debug_timestamp ? 1 : 0,
914                                             debug_show_keys ? 1 : 0)) {
915                 reply = wpas_dbus_error_invald_args(
916                         message, "Wrong debug level value");
917                 goto out;
918         }
919
920 out:
921         return reply;
922 }
923
924
925 /**
926  * wpas_dbus_getter_interfaces - Request registered interfaces list
927  * @message: Pointer to incoming dbus message
928  * @global: %wpa_supplicant global data structure
929  * Returns: The object paths array containing registered interfaces
930  * objects paths or DBus error on failure
931  *
932  * Getter for "Interfaces" property. Handles requests
933  * by dbus clients to return list of registered interfaces objects
934  * paths
935  */
936 DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message,
937                                           struct wpa_global *global)
938 {
939         DBusMessage *reply = NULL;
940         struct wpa_supplicant *wpa_s;
941         const char **paths;
942         unsigned int i = 0, num = 0;
943
944         for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
945                 num++;
946
947         paths = os_zalloc(num * sizeof(char*));
948         if (!paths) {
949                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
950                                               NULL);
951         }
952
953         for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
954                 paths[i] = wpas_dbus_get_path(wpa_s);
955
956         reply = wpas_dbus_simple_array_property_getter(message,
957                                                        DBUS_TYPE_OBJECT_PATH,
958                                                        paths, num);
959
960         os_free(paths);
961         return reply;
962 }
963
964
965 /**
966  * wpas_dbus_getter_eap_methods - Request supported EAP methods list
967  * @message: Pointer to incoming dbus message
968  * @nothing: not used argument. may be NULL or anything else
969  * Returns: The object paths array containing supported EAP methods
970  * represented by strings or DBus error on failure
971  *
972  * Getter for "EapMethods" property. Handles requests
973  * by dbus clients to return list of strings with supported EAP methods
974  */
975 DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message, void *nothing)
976 {
977         DBusMessage *reply = NULL;
978         char **eap_methods;
979         size_t num_items = 0;
980
981         eap_methods = eap_get_names_as_string_array(&num_items);
982         if (!eap_methods) {
983                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
984                                               NULL);
985         }
986
987         reply = wpas_dbus_simple_array_property_getter(message,
988                                                        DBUS_TYPE_STRING,
989                                                        eap_methods, num_items);
990
991         while (num_items)
992                 os_free(eap_methods[--num_items]);
993         os_free(eap_methods);
994         return reply;
995 }
996
997
998 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
999                                    char **type, DBusMessage **reply)
1000 {
1001         if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
1002                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1003                            "Type must be a string");
1004                 *reply = wpas_dbus_error_invald_args(
1005                         message, "Wrong Type value type. String required");
1006                 return -1;
1007         }
1008         dbus_message_iter_get_basic(var, type);
1009         return 0;
1010 }
1011
1012
1013 static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
1014                                     struct wpa_driver_scan_params *params,
1015                                     DBusMessage **reply)
1016 {
1017         struct wpa_driver_scan_ssid *ssids = params->ssids;
1018         size_t ssids_num = 0;
1019         u8 *ssid;
1020         DBusMessageIter array_iter, sub_array_iter;
1021         char *val;
1022         int len;
1023
1024         if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1025                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
1026                            "must be an array of arrays of bytes");
1027                 *reply = wpas_dbus_error_invald_args(
1028                         message, "Wrong SSIDs value type. Array of arrays of "
1029                         "bytes required");
1030                 return -1;
1031         }
1032
1033         dbus_message_iter_recurse(var, &array_iter);
1034
1035         if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1036             dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
1037         {
1038                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
1039                            "must be an array of arrays of bytes");
1040                 *reply = wpas_dbus_error_invald_args(
1041                         message, "Wrong SSIDs value type. Array of arrays of "
1042                         "bytes required");
1043                 return -1;
1044         }
1045
1046         while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
1047         {
1048                 if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
1049                         wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1050                                    "Too many ssids specified on scan dbus "
1051                                    "call");
1052                         *reply = wpas_dbus_error_invald_args(
1053                                 message, "Too many ssids specified. Specify "
1054                                 "at most four");
1055                         return -1;
1056                 }
1057
1058                 dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1059
1060                 dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1061                 if (len == 0) {
1062                         dbus_message_iter_next(&array_iter);
1063                         continue;
1064                 }
1065
1066                 ssid = os_malloc(len);
1067                 if (ssid == NULL) {
1068                         wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1069                                    "out of memory. Cannot allocate memory for "
1070                                    "SSID");
1071                         *reply = dbus_message_new_error(
1072                                 message, DBUS_ERROR_NO_MEMORY, NULL);
1073                         return -1;
1074                 }
1075                 os_memcpy(ssid, val, len);
1076                 ssids[ssids_num].ssid = ssid;
1077                 ssids[ssids_num].ssid_len = len;
1078
1079                 dbus_message_iter_next(&array_iter);
1080                 ssids_num++;
1081         }
1082
1083         params->num_ssids = ssids_num;
1084         return 0;
1085 }
1086
1087
1088 static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
1089                                   struct wpa_driver_scan_params *params,
1090                                   DBusMessage **reply)
1091 {
1092         u8 *ies = NULL, *nies;
1093         int ies_len = 0;
1094         DBusMessageIter array_iter, sub_array_iter;
1095         char *val;
1096         int len;
1097
1098         if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1099                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
1100                            "be an array of arrays of bytes");
1101                 *reply = wpas_dbus_error_invald_args(
1102                         message, "Wrong IEs value type. Array of arrays of "
1103                         "bytes required");
1104                 return -1;
1105         }
1106
1107         dbus_message_iter_recurse(var, &array_iter);
1108
1109         if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1110             dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
1111         {
1112                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
1113                            "be an array of arrays of bytes");
1114                 *reply = wpas_dbus_error_invald_args(
1115                         message, "Wrong IEs value type. Array required");
1116                 return -1;
1117         }
1118
1119         while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
1120         {
1121                 dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1122
1123                 dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1124                 if (len == 0) {
1125                         dbus_message_iter_next(&array_iter);
1126                         continue;
1127                 }
1128
1129                 nies = os_realloc(ies, ies_len + len);
1130                 if (nies == NULL) {
1131                         wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1132                                    "out of memory. Cannot allocate memory for "
1133                                    "IE");
1134                         os_free(ies);
1135                         *reply = dbus_message_new_error(
1136                                 message, DBUS_ERROR_NO_MEMORY, NULL);
1137                         return -1;
1138                 }
1139                 ies = nies;
1140                 os_memcpy(ies + ies_len, val, len);
1141                 ies_len += len;
1142
1143                 dbus_message_iter_next(&array_iter);
1144         }
1145
1146         params->extra_ies = ies;
1147         params->extra_ies_len = ies_len;
1148         return 0;
1149 }
1150
1151
1152 static int wpas_dbus_get_scan_channels(DBusMessage *message,
1153                                        DBusMessageIter *var,
1154                                        struct wpa_driver_scan_params *params,
1155                                        DBusMessage **reply)
1156 {
1157         DBusMessageIter array_iter, sub_array_iter;
1158         int *freqs = NULL, *nfreqs;
1159         int freqs_num = 0;
1160
1161         if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1162                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1163                            "Channels must be an array of structs");
1164                 *reply = wpas_dbus_error_invald_args(
1165                         message, "Wrong Channels value type. Array of structs "
1166                         "required");
1167                 return -1;
1168         }
1169
1170         dbus_message_iter_recurse(var, &array_iter);
1171
1172         if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
1173                 wpa_printf(MSG_DEBUG,
1174                            "wpas_dbus_handler_scan[dbus]: Channels must be an "
1175                            "array of structs");
1176                 *reply = wpas_dbus_error_invald_args(
1177                         message, "Wrong Channels value type. Array of structs "
1178                         "required");
1179                 return -1;
1180         }
1181
1182         while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
1183         {
1184                 int freq, width;
1185
1186                 dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1187
1188                 if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
1189                     DBUS_TYPE_UINT32) {
1190                         wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1191                                    "Channel must by specified by struct of "
1192                                    "two UINT32s %c",
1193                                    dbus_message_iter_get_arg_type(
1194                                            &sub_array_iter));
1195                         *reply = wpas_dbus_error_invald_args(
1196                                 message, "Wrong Channel struct. Two UINT32s "
1197                                 "required");
1198                         os_free(freqs);
1199                         return -1;
1200                 }
1201                 dbus_message_iter_get_basic(&sub_array_iter, &freq);
1202
1203                 if (!dbus_message_iter_next(&sub_array_iter) ||
1204                     dbus_message_iter_get_arg_type(&sub_array_iter) !=
1205                     DBUS_TYPE_UINT32) {
1206                         wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1207                                    "Channel must by specified by struct of "
1208                                    "two UINT32s");
1209                         *reply = wpas_dbus_error_invald_args(
1210                                 message,
1211                                 "Wrong Channel struct. Two UINT32s required");
1212                         os_free(freqs);
1213                         return -1;
1214                 }
1215
1216                 dbus_message_iter_get_basic(&sub_array_iter, &width);
1217
1218 #define FREQS_ALLOC_CHUNK 32
1219                 if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
1220                         nfreqs = os_realloc(freqs, sizeof(int) *
1221                                             (freqs_num + FREQS_ALLOC_CHUNK));
1222                         if (nfreqs == NULL)
1223                                 os_free(freqs);
1224                         freqs = nfreqs;
1225                 }
1226                 if (freqs == NULL) {
1227                         wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1228                                    "out of memory. can't allocate memory for "
1229                                    "freqs");
1230                         *reply = dbus_message_new_error(
1231                                 message, DBUS_ERROR_NO_MEMORY, NULL);
1232                         return -1;
1233                 }
1234
1235                 freqs[freqs_num] = freq;
1236
1237                 freqs_num++;
1238                 dbus_message_iter_next(&array_iter);
1239         }
1240
1241         nfreqs = os_realloc(freqs,
1242                             sizeof(int) * (freqs_num + 1));
1243         if (nfreqs == NULL)
1244                 os_free(freqs);
1245         freqs = nfreqs;
1246         if (freqs == NULL) {
1247                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1248                            "out of memory. Can't allocate memory for freqs");
1249                 *reply = dbus_message_new_error(
1250                         message, DBUS_ERROR_NO_MEMORY, NULL);
1251                 return -1;
1252         }
1253         freqs[freqs_num] = 0;
1254
1255         params->freqs = freqs;
1256         return 0;
1257 }
1258
1259
1260 /**
1261  * wpas_dbus_handler_scan - Request a wireless scan on an interface
1262  * @message: Pointer to incoming dbus message
1263  * @wpa_s: wpa_supplicant structure for a network interface
1264  * Returns: NULL indicating success or DBus error message on failure
1265  *
1266  * Handler function for "Scan" method call of a network device. Requests
1267  * that wpa_supplicant perform a wireless scan as soon as possible
1268  * on a particular wireless interface.
1269  */
1270 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
1271                                      struct wpa_supplicant *wpa_s)
1272 {
1273         DBusMessage *reply = NULL;
1274         DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
1275         char *key = NULL, *type = NULL;
1276         struct wpa_driver_scan_params params;
1277         size_t i;
1278
1279         os_memset(&params, 0, sizeof(params));
1280
1281         dbus_message_iter_init(message, &iter);
1282
1283         dbus_message_iter_recurse(&iter, &dict_iter);
1284
1285         while (dbus_message_iter_get_arg_type(&dict_iter) ==
1286                         DBUS_TYPE_DICT_ENTRY) {
1287                 dbus_message_iter_recurse(&dict_iter, &entry_iter);
1288                 dbus_message_iter_get_basic(&entry_iter, &key);
1289                 dbus_message_iter_next(&entry_iter);
1290                 dbus_message_iter_recurse(&entry_iter, &variant_iter);
1291
1292                 if (os_strcmp(key, "Type") == 0) {
1293                         if (wpas_dbus_get_scan_type(message, &variant_iter,
1294                                                     &type, &reply) < 0)
1295                                 goto out;
1296                 } else if (os_strcmp(key, "SSIDs") == 0) {
1297                         if (wpas_dbus_get_scan_ssids(message, &variant_iter,
1298                                                      &params, &reply) < 0)
1299                                 goto out;
1300                 } else if (os_strcmp(key, "IEs") == 0) {
1301                         if (wpas_dbus_get_scan_ies(message, &variant_iter,
1302                                                    &params, &reply) < 0)
1303                                 goto out;
1304                 } else if (os_strcmp(key, "Channels") == 0) {
1305                         if (wpas_dbus_get_scan_channels(message, &variant_iter,
1306                                                         &params, &reply) < 0)
1307                                 goto out;
1308                 } else {
1309                         wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1310                                    "Unknown argument %s", key);
1311                         reply = wpas_dbus_error_invald_args(message, key);
1312                         goto out;
1313                 }
1314
1315                 dbus_message_iter_next(&dict_iter);
1316         }
1317
1318         if (!type) {
1319                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1320                            "Scan type not specified");
1321                 reply = wpas_dbus_error_invald_args(message, key);
1322                 goto out;
1323         }
1324
1325         if (!os_strcmp(type, "passive")) {
1326                 if (params.num_ssids || params.extra_ies_len) {
1327                         wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1328                                    "SSIDs or IEs specified for passive scan.");
1329                         reply = wpas_dbus_error_invald_args(
1330                                 message, "You can specify only Channels in "
1331                                 "passive scan");
1332                         goto out;
1333                 } else if (params.freqs && params.freqs[0]) {
1334                         /* wildcard ssid */
1335                         params.num_ssids++;
1336                         wpa_supplicant_trigger_scan(wpa_s, &params);
1337                 } else {
1338                         wpa_s->scan_req = 2;
1339                         wpa_supplicant_req_scan(wpa_s, 0, 0);
1340                 }
1341         } else if (!os_strcmp(type, "active")) {
1342                 wpa_supplicant_trigger_scan(wpa_s, &params);
1343         } else {
1344                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
1345                            "Unknown scan type: %s", type);
1346                 reply = wpas_dbus_error_invald_args(message,
1347                                                     "Wrong scan type");
1348                 goto out;
1349         }
1350
1351 out:
1352         for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
1353                 os_free((u8 *) params.ssids[i].ssid);
1354         os_free((u8 *) params.extra_ies);
1355         os_free(params.freqs);
1356         return reply;
1357 }
1358
1359
1360 /*
1361  * wpas_dbus_handler_disconnect - Terminate the current connection
1362  * @message: Pointer to incoming dbus message
1363  * @wpa_s: wpa_supplicant structure for a network interface
1364  * Returns: NotConnected DBus error message if already not connected
1365  * or NULL otherwise.
1366  *
1367  * Handler function for "Disconnect" method call of network interface.
1368  */
1369 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
1370                                            struct wpa_supplicant *wpa_s)
1371 {
1372         if (wpa_s->current_ssid != NULL) {
1373                 wpa_s->disconnected = 1;
1374                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1375
1376                 return NULL;
1377         }
1378
1379         return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1380                                       "This interface is not connected");
1381 }
1382
1383
1384 /**
1385  * wpas_dbus_new_iface_add_network - Add a new configured network
1386  * @message: Pointer to incoming dbus message
1387  * @wpa_s: wpa_supplicant structure for a network interface
1388  * Returns: A dbus message containing the object path of the new network
1389  *
1390  * Handler function for "AddNetwork" method call of a network interface.
1391  */
1392 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
1393                                             struct wpa_supplicant *wpa_s)
1394 {
1395         DBusMessage *reply = NULL;
1396         DBusMessageIter iter;
1397         struct wpa_ssid *ssid = NULL;
1398         char *path = NULL;
1399
1400         path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1401         if (path == NULL) {
1402                 perror("wpas_dbus_handler_add_network[dbus]: out of "
1403                        "memory.");
1404                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1405                                                NULL);
1406                 goto err;
1407         }
1408
1409         dbus_message_iter_init(message, &iter);
1410
1411         ssid = wpa_config_add_network(wpa_s->conf);
1412         if (ssid == NULL) {
1413                 wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
1414                            "can't add new interface.");
1415                 reply = wpas_dbus_error_unknown_error(
1416                         message,
1417                         "wpa_supplicant could not add "
1418                         "a network on this interface.");
1419                 goto err;
1420         }
1421         wpas_notify_network_added(wpa_s, ssid);
1422         ssid->disabled = 1;
1423         wpa_config_set_network_defaults(ssid);
1424
1425         reply = set_network_properties(message, ssid, &iter);
1426         if (reply) {
1427                 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
1428                            "control interface couldn't set network "
1429                            "properties");
1430                 goto err;
1431         }
1432
1433         /* Construct the object path for this network. */
1434         os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1435                     "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
1436                     wpas_dbus_get_path(wpa_s),
1437                     ssid->id);
1438
1439         reply = dbus_message_new_method_return(message);
1440         if (reply == NULL) {
1441                 perror("wpas_dbus_handler_add_network[dbus]: out of memory "
1442                        "when creating reply");
1443                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1444                                                NULL);
1445                 goto err;
1446         }
1447         if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1448                                       DBUS_TYPE_INVALID)) {
1449                 perror("wpas_dbus_handler_add_network[dbus]: out of memory "
1450                        "when appending argument to reply");
1451                 dbus_message_unref(reply);
1452                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1453                                                NULL);
1454                 goto err;
1455         }
1456
1457         os_free(path);
1458         return reply;
1459
1460 err:
1461         if (ssid) {
1462                 wpas_notify_network_removed(wpa_s, ssid);
1463                 wpa_config_remove_network(wpa_s->conf, ssid->id);
1464         }
1465         os_free(path);
1466         return reply;
1467 }
1468
1469
1470 /**
1471  * wpas_dbus_handler_remove_network - Remove a configured network
1472  * @message: Pointer to incoming dbus message
1473  * @wpa_s: wpa_supplicant structure for a network interface
1474  * Returns: NULL on success or dbus error on failure
1475  *
1476  * Handler function for "RemoveNetwork" method call of a network interface.
1477  */
1478 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
1479                                                struct wpa_supplicant *wpa_s)
1480 {
1481         DBusMessage *reply = NULL;
1482         const char *op;
1483         char *iface = NULL, *net_id = NULL;
1484         int id;
1485         struct wpa_ssid *ssid;
1486
1487         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1488                               DBUS_TYPE_INVALID);
1489
1490         /* Extract the network ID and ensure the network */
1491         /* is actually a child of this interface */
1492         iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
1493         if (iface == NULL || strcmp(iface, wpas_dbus_get_path(wpa_s)) != 0) {
1494                 reply = wpas_dbus_error_invald_args(message, op);
1495                 goto out;
1496         }
1497
1498         id = strtoul(net_id, NULL, 10);
1499         if (errno == EINVAL) {
1500                 reply = wpas_dbus_error_invald_args(message, op);
1501                 goto out;
1502         }
1503
1504         ssid = wpa_config_get_network(wpa_s->conf, id);
1505         if (ssid == NULL) {
1506                 reply = wpas_dbus_error_network_unknown(message);
1507                 goto out;
1508         }
1509
1510         wpas_notify_network_removed(wpa_s, ssid);
1511
1512         if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1513                 wpa_printf(MSG_ERROR,
1514                            "wpas_dbus_handler_remove_network[dbus]: "
1515                            "error occurred when removing network %d", id);
1516                 reply = wpas_dbus_error_unknown_error(
1517                         message, "error removing the specified network on "
1518                         "this interface.");
1519                 goto out;
1520         }
1521
1522         if (ssid == wpa_s->current_ssid)
1523                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1524
1525 out:
1526         os_free(iface);
1527         os_free(net_id);
1528         return reply;
1529 }
1530
1531
1532 /**
1533  * wpas_dbus_handler_select_network - Attempt association with a network
1534  * @message: Pointer to incoming dbus message
1535  * @wpa_s: wpa_supplicant structure for a network interface
1536  * Returns: NULL on success or dbus error on failure
1537  *
1538  * Handler function for "SelectNetwork" method call of network interface.
1539  */
1540 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
1541                                                struct wpa_supplicant *wpa_s)
1542 {
1543         DBusMessage *reply = NULL;
1544         const char *op;
1545         char *iface = NULL, *net_id = NULL;
1546         int id;
1547         struct wpa_ssid *ssid;
1548
1549         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1550                               DBUS_TYPE_INVALID);
1551
1552         /* Extract the network ID and ensure the network */
1553         /* is actually a child of this interface */
1554         iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
1555         if (iface == NULL || strcmp(iface, wpas_dbus_get_path(wpa_s)) != 0) {
1556                 reply = wpas_dbus_error_invald_args(message, op);
1557                 goto out;
1558         }
1559
1560         id = strtoul(net_id, NULL, 10);
1561         if (errno == EINVAL) {
1562                 reply = wpas_dbus_error_invald_args(message, op);
1563                 goto out;
1564         }
1565
1566         ssid = wpa_config_get_network(wpa_s->conf, id);
1567         if (ssid == NULL) {
1568                 reply = wpas_dbus_error_network_unknown(message);
1569                 goto out;
1570         }
1571
1572         /* Finally, associate with the network */
1573         wpa_supplicant_select_network(wpa_s, ssid);
1574
1575 out:
1576         os_free(iface);
1577         os_free(net_id);
1578         return reply;
1579 }
1580
1581
1582 /**
1583  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
1584  * @message: Pointer to incoming dbus message
1585  * @wpa_s: %wpa_supplicant data structure
1586  * Returns: A dbus message containing an error on failure or NULL on success
1587  *
1588  * Asks wpa_supplicant to internally store a binary blobs.
1589  */
1590 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
1591                                          struct wpa_supplicant *wpa_s)
1592 {
1593         DBusMessage *reply = NULL;
1594         DBusMessageIter iter, array_iter;
1595
1596         char *blob_name;
1597         u8 *blob_data;
1598         int blob_len;
1599         struct wpa_config_blob *blob = NULL;
1600
1601         dbus_message_iter_init(message, &iter);
1602         dbus_message_iter_get_basic(&iter, &blob_name);
1603
1604         if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
1605                 return dbus_message_new_error(message,
1606                                               WPAS_DBUS_ERROR_BLOB_EXISTS,
1607                                               NULL);
1608         }
1609
1610         dbus_message_iter_next(&iter);
1611         dbus_message_iter_recurse(&iter, &array_iter);
1612
1613         dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
1614
1615         blob = os_zalloc(sizeof(*blob));
1616         if (!blob) {
1617                 perror("wpas_dbus_handler_add_blob[dbus] out of memory when "
1618                        "trying to allocate blob struct");
1619                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1620                                                NULL);
1621                 goto err;
1622         }
1623
1624         blob->data = os_malloc(blob_len);
1625         if (!blob->data) {
1626                 perror("wpas_dbus_handler_add_blob[dbus] out of memory when "
1627                        "trying to allocate blob data");
1628                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1629                                                NULL);
1630                 goto err;
1631         }
1632         os_memcpy(blob->data, blob_data, blob_len);
1633
1634         blob->len = blob_len;
1635         blob->name = os_strdup(blob_name);
1636         if (!blob->name) {
1637                 perror("wpas_dbus_handler_add_blob[dbus] out of memory when "
1638                        "trying to copy blob name");
1639                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1640                                                NULL);
1641                 goto err;
1642         }
1643
1644         wpa_config_set_blob(wpa_s->conf, blob);
1645         wpas_notify_blob_added(wpa_s, blob->name);
1646
1647         return reply;
1648
1649 err:
1650         if (blob) {
1651                 os_free(blob->name);
1652                 os_free(blob->data);
1653                 os_free(blob);
1654         }
1655         return reply;
1656 }
1657
1658
1659 /**
1660  * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
1661  * @message: Pointer to incoming dbus message
1662  * @wpa_s: %wpa_supplicant data structure
1663  * Returns: A dbus message containing array of bytes (blob)
1664  *
1665  * Gets one wpa_supplicant's binary blobs.
1666  */
1667 DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
1668                                          struct wpa_supplicant *wpa_s)
1669 {
1670         DBusMessage *reply = NULL;
1671         DBusMessageIter iter, array_iter;
1672
1673         char *blob_name;
1674         const struct wpa_config_blob *blob;
1675
1676         dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1677                               DBUS_TYPE_INVALID);
1678
1679         blob = wpa_config_get_blob(wpa_s->conf, blob_name);
1680         if (!blob) {
1681                 return dbus_message_new_error(message,
1682                                               WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1683                                               "Blob id not set");
1684         }
1685
1686         reply = dbus_message_new_method_return(message);
1687         if (!reply) {
1688                 perror("wpas_dbus_handler_get_blob[dbus] out of memory when "
1689                        "trying to allocate return message");
1690                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1691                                                NULL);
1692                 goto out;
1693         }
1694
1695         dbus_message_iter_init_append(reply, &iter);
1696
1697         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1698                                               DBUS_TYPE_BYTE_AS_STRING,
1699                                               &array_iter)) {
1700                 dbus_message_unref(reply);
1701                 perror("wpas_dbus_handler_get_blob[dbus] out of memory when "
1702                        "trying to open array");
1703                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1704                                                NULL);
1705                 goto out;
1706         }
1707
1708         if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
1709                                                   &(blob->data), blob->len)) {
1710                 dbus_message_unref(reply);
1711                 perror("wpas_dbus_handler_get_blob[dbus] out of memory when "
1712                        "trying to append data to array");
1713                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1714                                                NULL);
1715                 goto out;
1716         }
1717
1718         if (!dbus_message_iter_close_container(&iter, &array_iter)) {
1719                 dbus_message_unref(reply);
1720                 perror("wpas_dbus_handler_get_blob[dbus] out of memory when "
1721                        "trying to close array");
1722                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1723                                                NULL);
1724                 goto out;
1725         }
1726
1727 out:
1728         return reply;
1729 }
1730
1731
1732 /**
1733  * wpas_remove_handler_remove_blob - Remove named binary blob
1734  * @message: Pointer to incoming dbus message
1735  * @wpa_s: %wpa_supplicant data structure
1736  * Returns: NULL on success or dbus error
1737  *
1738  * Asks wpa_supplicant to internally remove a binary blobs.
1739  */
1740 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
1741                                             struct wpa_supplicant *wpa_s)
1742 {
1743         DBusMessage *reply = NULL;
1744         char *blob_name;
1745
1746         dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
1747                               DBUS_TYPE_INVALID);
1748
1749         if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
1750                 return dbus_message_new_error(message,
1751                                               WPAS_DBUS_ERROR_BLOB_UNKNOWN,
1752                                               "Blob id not set");
1753         }
1754         wpas_notify_blob_removed(wpa_s, blob_name);
1755
1756         return reply;
1757
1758 }
1759
1760
1761 /**
1762  * wpas_dbus_getter_capabilities - Return interface capabilities
1763  * @message: Pointer to incoming dbus message
1764  * @wpa_s: wpa_supplicant structure for a network interface
1765  * Returns: A dbus message containing a dict of strings
1766  *
1767  * Getter for "Capabilities" property of an interface.
1768  */
1769 DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
1770                                             struct wpa_supplicant *wpa_s)
1771 {
1772         DBusMessage *reply = NULL;
1773         struct wpa_driver_capa capa;
1774         int res;
1775         DBusMessageIter iter, iter_dict;
1776         DBusMessageIter iter_dict_entry, iter_dict_val, iter_array,
1777                 variant_iter;
1778         const char *scans[] = { "active", "passive", "ssid" };
1779         const char *modes[] = { "infrastructure", "ad-hoc", "ap" };
1780         int n = sizeof(modes) / sizeof(char *);
1781
1782         if (message == NULL)
1783                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1784         else
1785                 reply = dbus_message_new_method_return(message);
1786         if (!reply)
1787                 goto nomem;
1788
1789         dbus_message_iter_init_append(reply, &iter);
1790         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1791                                               "a{sv}", &variant_iter))
1792                 goto nomem;
1793
1794         if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
1795                 goto nomem;
1796
1797         res = wpa_drv_get_capa(wpa_s, &capa);
1798
1799         /***** pairwise cipher */
1800         if (res < 0) {
1801                 const char *args[] = {"ccmp", "tkip", "none"};
1802                 if (!wpa_dbus_dict_append_string_array(
1803                             &iter_dict, "Pairwise", args,
1804                             sizeof(args) / sizeof(char*)))
1805                         goto nomem;
1806         } else {
1807                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
1808                                                       &iter_dict_entry,
1809                                                       &iter_dict_val,
1810                                                       &iter_array))
1811                         goto nomem;
1812
1813                 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
1814                         if (!wpa_dbus_dict_string_array_add_element(
1815                                     &iter_array, "ccmp"))
1816                                 goto nomem;
1817                 }
1818
1819                 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
1820                         if (!wpa_dbus_dict_string_array_add_element(
1821                                     &iter_array, "tkip"))
1822                                 goto nomem;
1823                 }
1824
1825                 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1826                         if (!wpa_dbus_dict_string_array_add_element(
1827                                     &iter_array, "none"))
1828                                 goto nomem;
1829                 }
1830
1831                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
1832                                                     &iter_dict_entry,
1833                                                     &iter_dict_val,
1834                                                     &iter_array))
1835                         goto nomem;
1836         }
1837
1838         /***** group cipher */
1839         if (res < 0) {
1840                 const char *args[] = {
1841                         "ccmp", "tkip", "wep104", "wep40"
1842                 };
1843                 if (!wpa_dbus_dict_append_string_array(
1844                             &iter_dict, "Group", args,
1845                             sizeof(args) / sizeof(char*)))
1846                         goto nomem;
1847         } else {
1848                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
1849                                                       &iter_dict_entry,
1850                                                       &iter_dict_val,
1851                                                       &iter_array))
1852                         goto nomem;
1853
1854                 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
1855                         if (!wpa_dbus_dict_string_array_add_element(
1856                                     &iter_array, "ccmp"))
1857                                 goto nomem;
1858                 }
1859
1860                 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
1861                         if (!wpa_dbus_dict_string_array_add_element(
1862                                     &iter_array, "tkip"))
1863                                 goto nomem;
1864                 }
1865
1866                 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
1867                         if (!wpa_dbus_dict_string_array_add_element(
1868                                     &iter_array, "wep104"))
1869                                 goto nomem;
1870                 }
1871
1872                 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
1873                         if (!wpa_dbus_dict_string_array_add_element(
1874                                     &iter_array, "wep40"))
1875                                 goto nomem;
1876                 }
1877
1878                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
1879                                                     &iter_dict_entry,
1880                                                     &iter_dict_val,
1881                                                     &iter_array))
1882                         goto nomem;
1883         }
1884
1885         /***** key management */
1886         if (res < 0) {
1887                 const char *args[] = {
1888                         "wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
1889 #ifdef CONFIG_WPS
1890                         "wps",
1891 #endif /* CONFIG_WPS */
1892                         "none"
1893                 };
1894                 if (!wpa_dbus_dict_append_string_array(
1895                             &iter_dict, "KeyMgmt", args,
1896                             sizeof(args) / sizeof(char*)))
1897                         goto nomem;
1898         } else {
1899                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
1900                                                       &iter_dict_entry,
1901                                                       &iter_dict_val,
1902                                                       &iter_array))
1903                         goto nomem;
1904
1905                 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
1906                                                             "none"))
1907                         goto nomem;
1908
1909                 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
1910                                                             "ieee8021x"))
1911                         goto nomem;
1912
1913                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1914                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
1915                         if (!wpa_dbus_dict_string_array_add_element(
1916                                     &iter_array, "wpa-eap"))
1917                                 goto nomem;
1918                 }
1919
1920                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
1921                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1922                         if (!wpa_dbus_dict_string_array_add_element(
1923                                     &iter_array, "wpa-psk"))
1924                                 goto nomem;
1925                 }
1926
1927                 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1928                         if (!wpa_dbus_dict_string_array_add_element(
1929                                     &iter_array, "wpa-none"))
1930                                 goto nomem;
1931                 }
1932
1933
1934 #ifdef CONFIG_WPS
1935                 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
1936                                                             "wps"))
1937                         goto nomem;
1938 #endif /* CONFIG_WPS */
1939
1940                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
1941                                                     &iter_dict_entry,
1942                                                     &iter_dict_val,
1943                                                     &iter_array))
1944                         goto nomem;
1945         }
1946
1947         /***** WPA protocol */
1948         if (res < 0) {
1949                 const char *args[] = { "rsn", "wpa" };
1950                 if (!wpa_dbus_dict_append_string_array(
1951                             &iter_dict, "Protocol", args,
1952                             sizeof(args) / sizeof(char*)))
1953                         goto nomem;
1954         } else {
1955                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
1956                                                       &iter_dict_entry,
1957                                                       &iter_dict_val,
1958                                                       &iter_array))
1959                         goto nomem;
1960
1961                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1962                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1963                         if (!wpa_dbus_dict_string_array_add_element(
1964                                     &iter_array, "rsn"))
1965                                 goto nomem;
1966                 }
1967
1968                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1969                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
1970                         if (!wpa_dbus_dict_string_array_add_element(
1971                                     &iter_array, "wpa"))
1972                                 goto nomem;
1973                 }
1974
1975                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
1976                                                     &iter_dict_entry,
1977                                                     &iter_dict_val,
1978                                                     &iter_array))
1979                         goto nomem;
1980         }
1981
1982         /***** auth alg */
1983         if (res < 0) {
1984                 const char *args[] = { "open", "shared", "leap" };
1985                 if (!wpa_dbus_dict_append_string_array(
1986                             &iter_dict, "AuthAlg", args,
1987                             sizeof(args) / sizeof(char*)))
1988                         goto nomem;
1989         } else {
1990                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
1991                                                       &iter_dict_entry,
1992                                                       &iter_dict_val,
1993                                                       &iter_array))
1994                         goto nomem;
1995
1996                 if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
1997                         if (!wpa_dbus_dict_string_array_add_element(
1998                                     &iter_array, "open"))
1999                                 goto nomem;
2000                 }
2001
2002                 if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
2003                         if (!wpa_dbus_dict_string_array_add_element(
2004                                     &iter_array, "shared"))
2005                                 goto nomem;
2006                 }
2007
2008                 if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
2009                         if (!wpa_dbus_dict_string_array_add_element(
2010                                     &iter_array, "leap"))
2011                                 goto nomem;
2012                 }
2013
2014                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
2015                                                     &iter_dict_entry,
2016                                                     &iter_dict_val,
2017                                                     &iter_array))
2018                         goto nomem;
2019         }
2020
2021         /***** Scan */
2022         if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
2023                                                sizeof(scans) / sizeof(char *)))
2024                 goto nomem;
2025
2026         /***** Modes */
2027         if (res < 0 || !(capa.flags & WPA_DRIVER_FLAGS_AP))
2028                 n--; /* exclude ap mode if it is not supported by the driver */
2029         if (!wpa_dbus_dict_append_string_array(&iter_dict, "Modes", modes, n))
2030                 goto nomem;
2031
2032         if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
2033                 goto nomem;
2034         if (!dbus_message_iter_close_container(&iter, &variant_iter))
2035                 goto nomem;
2036
2037         return reply;
2038
2039 nomem:
2040         if (reply)
2041                 dbus_message_unref(reply);
2042
2043         return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
2044 }
2045
2046
2047 /**
2048  * wpas_dbus_getter_state - Get interface state
2049  * @message: Pointer to incoming dbus message
2050  * @wpa_s: wpa_supplicant structure for a network interface
2051  * Returns: A dbus message containing a STRING representing the current
2052  *          interface state
2053  *
2054  * Getter for "State" property.
2055  */
2056 DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
2057                                      struct wpa_supplicant *wpa_s)
2058 {
2059         DBusMessage *reply = NULL;
2060         const char *str_state;
2061         char *state_ls, *tmp;
2062
2063         str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
2064
2065         /* make state string lowercase to fit new DBus API convention
2066          */
2067         state_ls = tmp = os_strdup(str_state);
2068         if (!tmp) {
2069                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2070                                               NULL);
2071         }
2072         while (*tmp) {
2073                 *tmp = tolower(*tmp);
2074                 tmp++;
2075         }
2076
2077         reply = wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
2078                                                  &state_ls);
2079
2080         os_free(state_ls);
2081
2082         return reply;
2083 }
2084
2085
2086 /**
2087  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
2088  * @message: Pointer to incoming dbus message
2089  * @wpa_s: wpa_supplicant structure for a network interface
2090  * Returns: A dbus message containing whether the interface is scanning
2091  *
2092  * Getter for "scanning" property.
2093  */
2094 DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message,
2095                                         struct wpa_supplicant *wpa_s)
2096 {
2097         dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
2098         return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
2099                                                 &scanning);
2100 }
2101
2102
2103 /**
2104  * wpas_dbus_getter_ap_scan - Control roaming mode
2105  * @message: Pointer to incoming dbus message
2106  * @wpa_s: wpa_supplicant structure for a network interface
2107  * Returns: A message containong value of ap_scan variable
2108  *
2109  * Getter function for "ApScan" property.
2110  */
2111 DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message,
2112                                        struct wpa_supplicant *wpa_s)
2113 {
2114         dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
2115         return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32,
2116                                                 &ap_scan);
2117 }
2118
2119
2120 /**
2121  * wpas_dbus_setter_ap_scan - Control roaming mode
2122  * @message: Pointer to incoming dbus message
2123  * @wpa_s: wpa_supplicant structure for a network interface
2124  * Returns: NULL
2125  *
2126  * Setter function for "ApScan" property.
2127  */
2128 DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message,
2129                                        struct wpa_supplicant *wpa_s)
2130 {
2131         DBusMessage *reply = NULL;
2132         dbus_uint32_t ap_scan;
2133
2134         reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32,
2135                                                  &ap_scan);
2136         if (reply)
2137                 return reply;
2138
2139         if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
2140                 return wpas_dbus_error_invald_args(
2141                         message, "ap_scan must equal 0, 1 or 2");
2142         }
2143         return NULL;
2144 }
2145
2146
2147 /**
2148  * wpas_dbus_getter_ifname - Get interface name
2149  * @message: Pointer to incoming dbus message
2150  * @wpa_s: wpa_supplicant structure for a network interface
2151  * Returns: A dbus message containing a name of network interface
2152  * associated with with wpa_s
2153  *
2154  * Getter for "Ifname" property.
2155  */
2156 DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message,
2157                                       struct wpa_supplicant *wpa_s)
2158 {
2159         const char *ifname = wpa_s->ifname;
2160         return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
2161                                                 &ifname);
2162 }
2163
2164
2165 /**
2166  * wpas_dbus_getter_driver - Get interface name
2167  * @message: Pointer to incoming dbus message
2168  * @wpa_s: wpa_supplicant structure for a network interface
2169  * Returns: A dbus message containing a name of network interface
2170  * driver associated with with wpa_s
2171  *
2172  * Getter for "Driver" property.
2173  */
2174 DBusMessage * wpas_dbus_getter_driver(DBusMessage *message,
2175                                       struct wpa_supplicant *wpa_s)
2176 {
2177         const char *driver;
2178
2179         if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
2180                 wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
2181                            "wpa_s has no driver set");
2182                 return wpas_dbus_error_unknown_error(message, NULL);
2183         }
2184
2185         driver = wpa_s->driver->name;
2186         return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
2187                                                 &driver);
2188 }
2189
2190
2191 /**
2192  * wpas_dbus_getter_current_bss - Get current bss object path
2193  * @message: Pointer to incoming dbus message
2194  * @wpa_s: wpa_supplicant structure for a network interface
2195  * Returns: A dbus message containing a DBus object path to
2196  * current BSS
2197  *
2198  * Getter for "CurrentBSS" property.
2199  */
2200 DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message,
2201                                            struct wpa_supplicant *wpa_s)
2202 {
2203         DBusMessage *reply = NULL;
2204         const char *path = wpas_dbus_get_path(wpa_s);
2205         char *bss_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
2206         struct wpa_bss *bss = NULL;
2207
2208         if (bss_obj_path == NULL) {
2209                 perror("wpas_dbus_getter_current_bss[dbus]: out of "
2210                        "memory to allocate result argument.");
2211                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2212                                               NULL);
2213         }
2214
2215         /* TODO: store current BSS or BSS id in wpa_s */
2216         if (!is_zero_ether_addr(wpa_s->bssid))
2217                 bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
2218
2219         if (bss)
2220                 os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2221                             "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
2222                             path, bss->id);
2223         else
2224                 os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
2225
2226         reply = wpas_dbus_simple_property_getter(message,
2227                                                  DBUS_TYPE_OBJECT_PATH,
2228                                                  &bss_obj_path);
2229
2230         os_free(bss_obj_path);
2231         return reply;
2232 }
2233
2234
2235 /**
2236  * wpas_dbus_getter_current_network - Get current network object path
2237  * @message: Pointer to incoming dbus message
2238  * @wpa_s: wpa_supplicant structure for a network interface
2239  * Returns: A dbus message containing a DBus object path to
2240  * current network
2241  *
2242  * Getter for "CurrentNetwork" property.
2243  */
2244 DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
2245                                                struct wpa_supplicant *wpa_s)
2246 {
2247         DBusMessage *reply = NULL;
2248         const char *path = wpas_dbus_get_path(wpa_s);
2249         char *net_obj_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
2250
2251         if (net_obj_path == NULL) {
2252                 perror("wpas_dbus_getter_current_network[dbus]: out of "
2253                        "memory to allocate result argument.");
2254                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2255                                               NULL);
2256         }
2257
2258         if (wpa_s->current_ssid)
2259                 os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
2260                             "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", path,
2261                             wpa_s->current_ssid->id);
2262         else
2263                 os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
2264
2265         reply = wpas_dbus_simple_property_getter(message,
2266                                                  DBUS_TYPE_OBJECT_PATH,
2267                                                  &net_obj_path);
2268
2269         os_free(net_obj_path);
2270         return reply;
2271 }
2272
2273
2274 /**
2275  * wpas_dbus_getter_bridge_ifname - Get interface name
2276  * @message: Pointer to incoming dbus message
2277  * @wpa_s: wpa_supplicant structure for a network interface
2278  * Returns: A dbus message containing a name of bridge network
2279  * interface associated with with wpa_s
2280  *
2281  * Getter for "BridgeIfname" property.
2282  */
2283 DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message,
2284                                              struct wpa_supplicant *wpa_s)
2285 {
2286         const char *bridge_ifname = NULL;
2287
2288         bridge_ifname = wpa_s->bridge_ifname;
2289         if (bridge_ifname == NULL) {
2290                 wpa_printf(MSG_ERROR, "wpas_dbus_getter_bridge_ifname[dbus]: "
2291                            "wpa_s has no bridge interface name set");
2292                 return wpas_dbus_error_unknown_error(message, NULL);
2293         }
2294
2295         return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
2296                                                 &bridge_ifname);
2297 }
2298
2299
2300 /**
2301  * wpas_dbus_getter_bsss - Get array of BSSs objects
2302  * @message: Pointer to incoming dbus message
2303  * @wpa_s: wpa_supplicant structure for a network interface
2304  * Returns: a dbus message containing an array of all known BSS objects
2305  * dbus paths
2306  *
2307  * Getter for "BSSs" property.
2308  */
2309 DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
2310                                     struct wpa_supplicant *wpa_s)
2311 {
2312         DBusMessage *reply = NULL;
2313         struct wpa_bss *bss;
2314         char **paths;
2315         unsigned int i = 0;
2316
2317         paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
2318         if (!paths) {
2319                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2320                                               NULL);
2321         }
2322
2323         /* Loop through scan results and append each result's object path */
2324         dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
2325                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
2326                 if (paths[i] == NULL) {
2327                         perror("wpas_dbus_getter_bsss[dbus]: out of "
2328                                "memory.");
2329                         reply = dbus_message_new_error(message,
2330                                                        DBUS_ERROR_NO_MEMORY,
2331                                                        NULL);
2332                         goto out;
2333                 }
2334                 /* Construct the object path for this BSS. */
2335                 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
2336                             "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
2337                             wpas_dbus_get_path(wpa_s), bss->id);
2338         }
2339
2340         reply = wpas_dbus_simple_array_property_getter(message,
2341                                                        DBUS_TYPE_OBJECT_PATH,
2342                                                        paths, wpa_s->num_bss);
2343
2344 out:
2345         while(i)
2346                 os_free(paths[--i]);
2347         os_free(paths);
2348         return reply;
2349 }
2350
2351
2352 /**
2353  * wpas_dbus_getter_networks - Get array of networks objects
2354  * @message: Pointer to incoming dbus message
2355  * @wpa_s: wpa_supplicant structure for a network interface
2356  * Returns: a dbus message containing an array of all configured
2357  * networks dbus object paths.
2358  *
2359  * Getter for "Networks" property.
2360  */
2361 DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
2362                                         struct wpa_supplicant *wpa_s)
2363 {
2364         DBusMessage *reply = NULL;
2365         struct wpa_ssid *ssid;
2366         char **paths;
2367         unsigned int i = 0, num = 0;
2368
2369         if (wpa_s->conf == NULL) {
2370                 wpa_printf(MSG_ERROR, "wpas_dbus_getter_networks[dbus]: "
2371                            "An error occurred getting networks list.");
2372                 return wpas_dbus_error_unknown_error(message, NULL);
2373         }
2374
2375         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
2376                 num++;
2377
2378         paths = os_zalloc(num * sizeof(char *));
2379         if (!paths) {
2380                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2381                                               NULL);
2382         }
2383
2384         /* Loop through configured networks and append object path of each */
2385         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
2386
2387                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
2388                 if (paths[i] == NULL) {
2389                         perror("wpas_dbus_getter_networks[dbus]: out of "
2390                                "memory.");
2391                         reply = dbus_message_new_error(message,
2392                                                        DBUS_ERROR_NO_MEMORY,
2393                                                        NULL);
2394                         goto out;
2395                 }
2396
2397                 /* Construct the object path for this network. */
2398                 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
2399                             "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
2400                             wpas_dbus_get_path(wpa_s), ssid->id);
2401         }
2402
2403         reply = wpas_dbus_simple_array_property_getter(message,
2404                                                        DBUS_TYPE_OBJECT_PATH,
2405                                                        paths, num);
2406
2407 out:
2408         while (i)
2409                 os_free(paths[--i]);
2410         os_free(paths);
2411         return reply;
2412 }
2413
2414
2415 /**
2416  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
2417  * @message: Pointer to incoming dbus message
2418  * @wpa_s: wpa_supplicant structure for a network interface
2419  * Returns: a dbus message containing a dictionary of pairs (blob_name, blob)
2420  *
2421  * Getter for "Blobs" property.
2422  */
2423 DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
2424                                      struct wpa_supplicant *wpa_s)
2425 {
2426         DBusMessage *reply = NULL;
2427         DBusMessageIter iter, variant_iter, dict_iter, entry_iter, array_iter;
2428         struct wpa_config_blob *blob;
2429
2430         if (message == NULL)
2431                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
2432         else
2433                 reply = dbus_message_new_method_return(message);
2434         if (!reply) {
2435                 perror("wpas_dbus_getter_blobs[dbus] out of memory when "
2436                        "trying to initialize return message");
2437                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2438                                                NULL);
2439                 goto out;
2440         }
2441
2442         dbus_message_iter_init_append(reply, &iter);
2443
2444         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
2445                                               "a{say}", &variant_iter)) {
2446                 dbus_message_unref(reply);
2447                 perror("wpas_dbus_getter_blobs[dbus] out of memory when "
2448                        "trying to open variant");
2449                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2450                                                NULL);
2451                 goto out;
2452         }
2453
2454         if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
2455                                               "{say}", &dict_iter)) {
2456                 dbus_message_unref(reply);
2457                 perror("wpas_dbus_getter_blobs[dbus] out of memory when "
2458                        "trying to open dictionary");
2459                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2460                                                NULL);
2461                 goto out;
2462         }
2463
2464         blob = wpa_s->conf->blobs;
2465         while (blob) {
2466                 if (!dbus_message_iter_open_container(&dict_iter,
2467                                                       DBUS_TYPE_DICT_ENTRY,
2468                                                       NULL, &entry_iter)) {
2469                         dbus_message_unref(reply);
2470                         perror("wpas_dbus_getter_blobs[dbus] out of memory "
2471                                "when trying to open entry");
2472                         reply = dbus_message_new_error(message,
2473                                                        DBUS_ERROR_NO_MEMORY,
2474                                                        NULL);
2475                         goto out;
2476                 }
2477
2478                 if (!dbus_message_iter_append_basic(&entry_iter,
2479                                                     DBUS_TYPE_STRING,
2480                                                     &(blob->name))) {
2481                         dbus_message_unref(reply);
2482                         perror("wpas_dbus_getter_blobs[dbus] out of memory "
2483                                "when trying to append blob name");
2484                         reply = dbus_message_new_error(message,
2485                                                        DBUS_ERROR_NO_MEMORY,
2486                                                        NULL);
2487                         goto out;
2488                 }
2489
2490                 if (!dbus_message_iter_open_container(&entry_iter,
2491                                                       DBUS_TYPE_ARRAY,
2492                                                       DBUS_TYPE_BYTE_AS_STRING,
2493                                                       &array_iter)) {
2494                         dbus_message_unref(reply);
2495                         perror("wpas_dbus_getter_blobs[dbus] out of memory "
2496                                "when trying to open array");
2497                         reply = dbus_message_new_error(message,
2498                                                        DBUS_ERROR_NO_MEMORY,
2499                                                        NULL);
2500                         goto out;
2501                 }
2502
2503                 if (!dbus_message_iter_append_fixed_array(&array_iter,
2504                                                           DBUS_TYPE_BYTE,
2505                                                           &(blob->data),
2506                                                           blob->len)) {
2507                         dbus_message_unref(reply);
2508                         perror("wpas_dbus_getter_blobs[dbus] out of memory "
2509                                "when trying to append blob data");
2510                         reply = dbus_message_new_error(message,
2511                                                        DBUS_ERROR_NO_MEMORY,
2512                                                        NULL);
2513                         goto out;
2514                 }
2515
2516                 if (!dbus_message_iter_close_container(&entry_iter,
2517                                                        &array_iter)) {
2518                         dbus_message_unref(reply);
2519                         perror("wpas_dbus_getter_blobs[dbus] out of memory "
2520                                "when trying to close array");
2521                         reply = dbus_message_new_error(message,
2522                                                        DBUS_ERROR_NO_MEMORY,
2523                                                        NULL);
2524                         goto out;
2525                 }
2526
2527                 if (!dbus_message_iter_close_container(&dict_iter,
2528                                                        &entry_iter)) {
2529                         dbus_message_unref(reply);
2530                         perror("wpas_dbus_getter_blobs[dbus] out of memory "
2531                                "when trying to close entry");
2532                         reply = dbus_message_new_error(message,
2533                                                        DBUS_ERROR_NO_MEMORY,
2534                                                        NULL);
2535                         goto out;
2536                 }
2537
2538                 blob = blob->next;
2539         }
2540
2541         if (!dbus_message_iter_close_container(&variant_iter, &dict_iter)) {
2542                 dbus_message_unref(reply);
2543                 perror("wpas_dbus_getter_blobs[dbus] out of memory when "
2544                        "trying to close dictionary");
2545                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2546                                                NULL);
2547                 goto out;
2548         }
2549
2550         if (!dbus_message_iter_close_container(&iter, &variant_iter)) {
2551                 dbus_message_unref(reply);
2552                 perror("wpas_dbus_getter_blobs[dbus] out of memory when "
2553                        "trying to close variant");
2554                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2555                                                NULL);
2556                 goto out;
2557         }
2558
2559 out:
2560         return reply;
2561 }
2562
2563
2564 /**
2565  * wpas_dbus_getter_bss_properties - Return the properties of a scanned bss
2566  * @message: Pointer to incoming dbus message
2567  * @bss: a pair of interface describing structure and bss' bssid
2568  * Returns: a dbus message containing the properties for the requested bss
2569  *
2570  * Getter for "Properties" property.
2571  */
2572 DBusMessage * wpas_dbus_getter_bss_properties(DBusMessage *message,
2573                                               struct bss_handler_args *bss)
2574 {
2575         DBusMessage *reply = NULL;
2576         DBusMessageIter iter, iter_dict, variant_iter;
2577         const u8 *ie;
2578         struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
2579
2580         if (res == NULL)
2581                 return NULL;
2582
2583         /* Dump the properties into a dbus message */
2584         if (message == NULL)
2585                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
2586         else
2587                 reply = dbus_message_new_method_return(message);
2588
2589         if (!reply)
2590                 goto error;
2591
2592         dbus_message_iter_init_append(reply, &iter);
2593
2594         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
2595                                               "a{sv}", &variant_iter))
2596                 goto error;
2597
2598         if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
2599                 goto error;
2600
2601         if (!wpa_dbus_dict_append_byte_array(&iter_dict, "BSSID",
2602                                              (const char *) res->bssid,
2603                                              ETH_ALEN))
2604                 goto error;
2605
2606         ie = wpa_bss_get_ie(res, WLAN_EID_SSID);
2607         if (ie) {
2608                 if (!wpa_dbus_dict_append_byte_array(&iter_dict, "SSID",
2609                                                      (const char *) (ie + 2),
2610                                                      ie[1]))
2611                 goto error;
2612         }
2613
2614         ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
2615         if (ie) {
2616                 if (!wpa_dbus_dict_append_byte_array(&iter_dict, "WPAIE",
2617                                                      (const char *) ie,
2618                                                      ie[1] + 2))
2619                         goto error;
2620         }
2621
2622         ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
2623         if (ie) {
2624                 if (!wpa_dbus_dict_append_byte_array(&iter_dict, "RSNIE",
2625                                                      (const char *) ie,
2626                                                      ie[1] + 2))
2627                         goto error;
2628         }
2629
2630         ie = wpa_bss_get_vendor_ie(res, WPS_IE_VENDOR_TYPE);
2631         if (ie) {
2632                 if (!wpa_dbus_dict_append_byte_array(&iter_dict, "WPSIE",
2633                                                      (const char *) ie,
2634                                                      ie[1] + 2))
2635                         goto error;
2636         }
2637
2638         if (res->freq) {
2639                 if (!wpa_dbus_dict_append_int32(&iter_dict, "Frequency",
2640                                                 res->freq))
2641                         goto error;
2642         }
2643         if (!wpa_dbus_dict_append_uint16(&iter_dict, "Capabilities",
2644                                          res->caps))
2645                 goto error;
2646         if (!(res->flags & WPA_SCAN_QUAL_INVALID) &&
2647             !wpa_dbus_dict_append_int32(&iter_dict, "Quality", res->qual))
2648                 goto error;
2649         if (!(res->flags & WPA_SCAN_NOISE_INVALID) &&
2650             !wpa_dbus_dict_append_int32(&iter_dict, "Noise", res->noise))
2651                 goto error;
2652         if (!(res->flags & WPA_SCAN_LEVEL_INVALID) &&
2653             !wpa_dbus_dict_append_int32(&iter_dict, "Level", res->level))
2654                 goto error;
2655         if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxRate",
2656                                         wpa_bss_get_max_rate(res) * 500000))
2657                 goto error;
2658
2659         if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
2660                 goto error;
2661
2662         return reply;
2663
2664 error:
2665         if (reply)
2666                 dbus_message_unref(reply);
2667         return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
2668 }
2669
2670
2671 /**
2672  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
2673  * @message: Pointer to incoming dbus message
2674  * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
2675  * and wpa_ssid structure for a configured network
2676  * Returns: DBus message with boolean indicating state of configured network
2677  * or DBus error on failure
2678  *
2679  * Getter for "enabled" property of a configured network.
2680  */
2681 DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message,
2682                                        struct network_handler_args *net)
2683 {
2684         dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
2685         return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
2686                                                 &enabled);
2687 }
2688
2689
2690 /**
2691  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
2692  * @message: Pointer to incoming dbus message
2693  * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
2694  * and wpa_ssid structure for a configured network
2695  * Returns: NULL indicating success or DBus error on failure
2696  *
2697  * Setter for "Enabled" property of a configured network.
2698  */
2699 DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
2700                                        struct network_handler_args *net)
2701 {
2702         DBusMessage *reply = NULL;
2703
2704         struct wpa_supplicant *wpa_s;
2705         struct wpa_ssid *ssid;
2706
2707         dbus_bool_t enable;
2708
2709         reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
2710                                                  &enable);
2711
2712         if (reply)
2713                 return reply;
2714
2715         wpa_s = net->wpa_s;
2716         ssid = net->ssid;
2717
2718         if (enable)
2719                 wpa_supplicant_enable_network(wpa_s, ssid);
2720         else
2721                 wpa_supplicant_disable_network(wpa_s, ssid);
2722
2723         return NULL;
2724 }
2725
2726
2727 /**
2728  * wpas_dbus_getter_network_properties - Get options for a configured network
2729  * @message: Pointer to incoming dbus message
2730  * @net: wpa_supplicant structure for a network interface and
2731  * wpa_ssid structure for a configured network
2732  * Returns: DBus message with network properties or DBus error on failure
2733  *
2734  * Getter for "Properties" property of a configured network.
2735  */
2736 DBusMessage * wpas_dbus_getter_network_properties(
2737         DBusMessage *message, struct network_handler_args *net)
2738 {
2739         DBusMessage *reply = NULL;
2740         DBusMessageIter iter, variant_iter, dict_iter;
2741         char **iterator;
2742         char **props = wpa_config_get_all(net->ssid, 0);
2743         if (!props) {
2744                 perror("wpas_dbus_getter_network_properties[dbus] couldn't "
2745                        "read network properties. out of memory.");
2746                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2747                                               NULL);
2748         }
2749
2750         if (message == NULL)
2751                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
2752         else
2753                 reply = dbus_message_new_method_return(message);
2754         if (!reply) {
2755                 perror("wpas_dbus_getter_network_properties[dbus] out of "
2756                        "memory when trying to initialize return message");
2757                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2758                                                NULL);
2759                 goto out;
2760         }
2761
2762         dbus_message_iter_init_append(reply, &iter);
2763
2764         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
2765                         "a{sv}", &variant_iter)) {
2766                 perror("wpas_dbus_getter_network_properties[dbus] out of "
2767                        "memory when trying to open variant container");
2768                 dbus_message_unref(reply);
2769                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2770                                                NULL);
2771                 goto out;
2772         }
2773
2774         if (!wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
2775                 perror("wpas_dbus_getter_network_properties[dbus] out of "
2776                        "memory when trying to open dict");
2777                 dbus_message_unref(reply);
2778                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2779                                                NULL);
2780                 goto out;
2781         }
2782
2783         iterator = props;
2784         while (*iterator) {
2785                 if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
2786                                                  *(iterator + 1))) {
2787                         perror("wpas_dbus_getter_network_properties[dbus] out "
2788                                "of memory when trying to add entry");
2789                         dbus_message_unref(reply);
2790                         reply = dbus_message_new_error(message,
2791                                                        DBUS_ERROR_NO_MEMORY,
2792                                                        NULL);
2793                         goto out;
2794                 }
2795                 iterator += 2;
2796         }
2797
2798
2799         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter)) {
2800                 perror("wpas_dbus_getter_network_properties[dbus] out of "
2801                        "memory when trying to close dictionary");
2802                 dbus_message_unref(reply);
2803                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2804                                                NULL);
2805                 goto out;
2806         }
2807
2808         if (!dbus_message_iter_close_container(&iter, &variant_iter)) {
2809                 perror("wpas_dbus_getter_network_properties[dbus] out of "
2810                        "memory when trying to close variant container");
2811                 dbus_message_unref(reply);
2812                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
2813                                                NULL);
2814                 goto out;
2815         }
2816
2817 out:
2818         iterator = props;
2819         while (*iterator) {
2820                 os_free(*iterator);
2821                 iterator++;
2822         }
2823         os_free(props);
2824         return reply;
2825 }
2826
2827
2828 /**
2829  * wpas_dbus_setter_network_properties - Set options for a configured network
2830  * @message: Pointer to incoming dbus message
2831  * @net: wpa_supplicant structure for a network interface and
2832  * wpa_ssid structure for a configured network
2833  * Returns: NULL indicating success or DBus error on failure
2834  *
2835  * Setter for "Properties" property of a configured network.
2836  */
2837 DBusMessage * wpas_dbus_setter_network_properties(
2838         DBusMessage *message, struct network_handler_args *net)
2839 {
2840         struct wpa_ssid *ssid = net->ssid;
2841
2842         DBusMessage *reply = NULL;
2843         DBusMessageIter iter, variant_iter;
2844
2845         dbus_message_iter_init(message, &iter);
2846
2847         dbus_message_iter_next(&iter);
2848         dbus_message_iter_next(&iter);
2849
2850         dbus_message_iter_recurse(&iter, &variant_iter);
2851
2852         reply = set_network_properties(message, ssid, &variant_iter);
2853         if (reply)
2854                 wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
2855                            "network properties");
2856
2857         return reply;
2858 }