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