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