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