Update supplicant test program with some API changes
[framework/connectivity/connman.git] / tools / supplicant.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
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  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <syslog.h>
30
31 #include <glib.h>
32 #include <gdbus.h>
33
34 #include "supplicant-dbus.h"
35 #include "supplicant.h"
36
37 #define DBG(fmt, arg...) do { \
38         syslog(LOG_DEBUG, "%s() " fmt, __FUNCTION__ , ## arg); \
39 } while (0)
40
41 #define TIMEOUT 5000
42
43 #define IEEE80211_CAP_ESS       0x0001
44 #define IEEE80211_CAP_IBSS      0x0002
45 #define IEEE80211_CAP_PRIVACY   0x0010
46
47 static DBusConnection *connection;
48
49 static const struct supplicant_callbacks *callbacks_pointer;
50
51 static dbus_bool_t system_available = FALSE;
52 static dbus_bool_t system_ready = FALSE;
53
54 static dbus_int32_t debug_level = 0;
55 static dbus_bool_t debug_timestamp = FALSE;
56 static dbus_bool_t debug_showkeys = FALSE;
57
58 static unsigned int eap_methods;
59
60 struct strvalmap {
61         const char *str;
62         unsigned int val;
63 };
64
65 static struct strvalmap eap_method_map[] = {
66         { "MD5",        SUPPLICANT_EAP_METHOD_MD5       },
67         { "TLS",        SUPPLICANT_EAP_METHOD_TLS       },
68         { "MSCHAPV2",   SUPPLICANT_EAP_METHOD_MSCHAPV2  },
69         { "PEAP",       SUPPLICANT_EAP_METHOD_PEAP      },
70         { "TTLS",       SUPPLICANT_EAP_METHOD_TTLS      },
71         { "GTC",        SUPPLICANT_EAP_METHOD_GTC       },
72         { "OTP",        SUPPLICANT_EAP_METHOD_OTP       },
73         { "LEAP",       SUPPLICANT_EAP_METHOD_LEAP      },
74         { }
75 };
76
77 static struct strvalmap keymgmt_capa_map[] = {
78         { "none",       SUPPLICANT_CAPABILITY_KEYMGMT_NONE      },
79         { "ieee8021x",  SUPPLICANT_CAPABILITY_KEYMGMT_IEEE8021X },
80         { "wpa-none",   SUPPLICANT_CAPABILITY_KEYMGMT_WPA_NONE  },
81         { "wpa-psk",    SUPPLICANT_CAPABILITY_KEYMGMT_WPA_PSK   },
82         { "wpa-eap",    SUPPLICANT_CAPABILITY_KEYMGMT_WPA_EAP   },
83         { "wps",        SUPPLICANT_CAPABILITY_KEYMGMT_WPS       },
84         { }
85 };
86
87 static struct strvalmap authalg_capa_map[] = {
88         { "open",       SUPPLICANT_CAPABILITY_AUTHALG_OPEN      },
89         { "shared",     SUPPLICANT_CAPABILITY_AUTHALG_SHARED    },
90         { "leap",       SUPPLICANT_CAPABILITY_AUTHALG_LEAP      },
91         { }
92 };
93
94 static struct strvalmap proto_capa_map[] = {
95         { "wpa",        SUPPLICANT_CAPABILITY_PROTO_WPA         },
96         { "rsn",        SUPPLICANT_CAPABILITY_PROTO_RSN         },
97         { }
98 };
99
100 static struct strvalmap scan_capa_map[] = {
101         { "active",     SUPPLICANT_CAPABILITY_SCAN_ACTIVE       },
102         { "passive",    SUPPLICANT_CAPABILITY_SCAN_PASSIVE      },
103         { "ssid",       SUPPLICANT_CAPABILITY_SCAN_SSID         },
104         { }
105 };
106
107 static struct strvalmap mode_capa_map[] = {
108         { "infrastructure",     SUPPLICANT_CAPABILITY_MODE_INFRA        },
109         { "ad-hoc",             SUPPLICANT_CAPABILITY_MODE_IBSS         },
110         { "ap",                 SUPPLICANT_CAPABILITY_MODE_AP           },
111         { }
112 };
113
114 static GHashTable *interface_table;
115
116 struct supplicant_interface {
117         char *path;
118         unsigned int keymgmt_capa;
119         unsigned int authalg_capa;
120         unsigned int proto_capa;
121         unsigned int scan_capa;
122         unsigned int mode_capa;
123         enum supplicant_state state;
124         dbus_bool_t scanning;
125         int apscan;
126         char *ifname;
127         char *driver;
128         char *bridge;
129         GHashTable *network_table;
130         GHashTable *bss_mapping;
131 };
132
133 struct supplicant_network {
134         struct supplicant_interface *interface;
135         char *group;
136         char *name;
137         enum supplicant_mode mode;
138         GHashTable *bss_table;
139 };
140
141 struct supplicant_bss {
142         struct supplicant_interface *interface;
143         char *path;
144         unsigned char bssid[6];
145         unsigned char ssid[32];
146         unsigned int ssid_len;
147         dbus_uint16_t frequency;
148         enum supplicant_mode mode;
149         enum supplicant_security security;
150         dbus_bool_t privacy;
151         dbus_bool_t psk;
152         dbus_bool_t ieee8021x;
153 };
154
155 static enum supplicant_mode string2mode(const char *mode)
156 {
157         if (mode == NULL)
158                 return SUPPLICANT_MODE_UNKNOWN;
159
160         if (g_str_equal(mode, "infrastructure") == TRUE)
161                 return SUPPLICANT_MODE_INFRA;
162         else if (g_str_equal(mode, "ad-hoc") == TRUE)
163                 return SUPPLICANT_MODE_IBSS;
164
165         return SUPPLICANT_MODE_UNKNOWN;
166 }
167
168 static const char *mode2string(enum supplicant_mode mode)
169 {
170         switch (mode) {
171         case SUPPLICANT_MODE_UNKNOWN:
172                 break;
173         case SUPPLICANT_MODE_INFRA:
174                 return "managed";
175         case SUPPLICANT_MODE_IBSS:
176                 return "adhoc";
177         }
178
179         return NULL;
180 }
181
182 static const char *security2string(enum supplicant_security security)
183 {
184         switch (security) {
185         case SUPPLICANT_SECURITY_UNKNOWN:
186                 break;
187         case SUPPLICANT_SECURITY_NONE:
188                 return "none";
189         case SUPPLICANT_SECURITY_WEP:
190                 return "wep";
191         case SUPPLICANT_SECURITY_PSK:
192                 return "psk";
193         case SUPPLICANT_SECURITY_IEEE8021X:
194                 return "ieee8021x";
195         }
196
197         return NULL;
198 }
199
200 static enum supplicant_state string2state(const char *state)
201 {
202         if (state == NULL)
203                 return SUPPLICANT_STATE_UNKNOWN;
204
205         if (g_str_equal(state, "unknown") == TRUE)
206                 return SUPPLICANT_STATE_UNKNOWN;
207         else if (g_str_equal(state, "disconnected") == TRUE)
208                 return SUPPLICANT_STATE_DISCONNECTED;
209         else if (g_str_equal(state, "inactive") == TRUE)
210                 return SUPPLICANT_STATE_INACTIVE;
211         else if (g_str_equal(state, "scanning") == TRUE)
212                 return SUPPLICANT_STATE_SCANNING;
213         else if (g_str_equal(state, "authenticating") == TRUE)
214                 return SUPPLICANT_STATE_AUTHENTICATING;
215         else if (g_str_equal(state, "associating") == TRUE)
216                 return SUPPLICANT_STATE_ASSOCIATING;
217         else if (g_str_equal(state, "associated") == TRUE)
218                 return SUPPLICANT_STATE_ASSOCIATED;
219         else if (g_str_equal(state, "group_handshake") == TRUE)
220                 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
221         else if (g_str_equal(state, "4way_handshake") == TRUE)
222                 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
223         else if (g_str_equal(state, "completed") == TRUE)
224                 return SUPPLICANT_STATE_COMPLETED;
225
226         return SUPPLICANT_STATE_UNKNOWN;
227 }
228
229 static void callback_system_ready(void)
230 {
231         if (system_ready == TRUE)
232                 return;
233
234         system_ready = TRUE;
235
236         if (callbacks_pointer == NULL)
237                 return;
238
239         if (callbacks_pointer->system_ready == NULL)
240                 return;
241
242         callbacks_pointer->system_ready();
243 }
244
245 static void callback_system_killed(void)
246 {
247         system_ready = FALSE;
248
249         if (callbacks_pointer == NULL)
250                 return;
251
252         if (callbacks_pointer->system_killed == NULL)
253                 return;
254
255         callbacks_pointer->system_killed();
256 }
257
258 static void callback_interface_added(struct supplicant_interface *interface)
259 {
260         if (callbacks_pointer == NULL)
261                 return;
262
263         if (callbacks_pointer->interface_added == NULL)
264                 return;
265
266         callbacks_pointer->interface_added(interface);
267 }
268
269 static void callback_interface_removed(struct supplicant_interface *interface)
270 {
271         if (callbacks_pointer == NULL)
272                 return;
273
274         if (callbacks_pointer->interface_removed == NULL)
275                 return;
276
277         callbacks_pointer->interface_removed(interface);
278 }
279
280 static void callback_network_added(struct supplicant_network *network)
281 {
282         if (callbacks_pointer == NULL)
283                 return;
284
285         if (callbacks_pointer->network_added == NULL)
286                 return;
287
288         callbacks_pointer->network_added(network);
289 }
290
291 static void callback_network_removed(struct supplicant_network *network)
292 {
293         if (callbacks_pointer == NULL)
294                 return;
295
296         if (callbacks_pointer->network_removed == NULL)
297                 return;
298
299         callbacks_pointer->network_removed(network);
300 }
301
302 static void remove_interface(gpointer data)
303 {
304         struct supplicant_interface *interface = data;
305
306         g_hash_table_destroy(interface->bss_mapping);
307         g_hash_table_destroy(interface->network_table);
308
309         callback_interface_removed(interface);
310
311         g_free(interface->path);
312         g_free(interface->ifname);
313         g_free(interface->driver);
314         g_free(interface->bridge);
315         g_free(interface);
316 }
317
318 static void remove_network(gpointer data)
319 {
320         struct supplicant_network *network = data;
321
322         callback_network_removed(network);
323
324         g_free(network->group);
325         g_free(network->name);
326         g_free(network);
327 }
328
329 static void remove_bss(gpointer data)
330 {
331         struct supplicant_bss *bss = data;
332
333         g_free(bss->path);
334         g_free(bss);
335 }
336
337 static void debug_strvalmap(const char *label, struct strvalmap *map,
338                                                         unsigned int val)
339 {
340         int i;
341
342         for (i = 0; map[i].str != NULL; i++) {
343                 if (val & map[i].val)
344                         DBG("%s: %s", label, map[i].str);
345         }
346 }
347
348 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
349 {
350         struct supplicant_interface *interface = user_data;
351         const char *str = NULL;
352         int i;
353
354         dbus_message_iter_get_basic(iter, &str);
355         if (str == NULL)
356                 return;
357
358         for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
359                 if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
360                         interface->keymgmt_capa |= keymgmt_capa_map[i].val;
361                         break;
362                 }
363 }
364
365 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
366 {
367         struct supplicant_interface *interface = user_data;
368         const char *str = NULL;
369         int i;
370
371         dbus_message_iter_get_basic(iter, &str);
372         if (str == NULL)
373                 return;
374
375         for (i = 0; authalg_capa_map[i].str != NULL; i++)
376                 if (strcmp(str, authalg_capa_map[i].str) == 0) {
377                         interface->authalg_capa |= authalg_capa_map[i].val;
378                         break;
379                 }
380 }
381
382 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
383 {
384         struct supplicant_interface *interface = user_data;
385         const char *str = NULL;
386         int i;
387
388         dbus_message_iter_get_basic(iter, &str);
389         if (str == NULL)
390                 return;
391
392         for (i = 0; proto_capa_map[i].str != NULL; i++)
393                 if (strcmp(str, proto_capa_map[i].str) == 0) {
394                         interface->proto_capa |= proto_capa_map[i].val;
395                         break;
396                 }
397 }
398
399 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
400 {
401         struct supplicant_interface *interface = user_data;
402         const char *str = NULL;
403         int i;
404
405         dbus_message_iter_get_basic(iter, &str);
406         if (str == NULL)
407                 return;
408
409         for (i = 0; scan_capa_map[i].str != NULL; i++)
410                 if (strcmp(str, scan_capa_map[i].str) == 0) {
411                         interface->scan_capa |= scan_capa_map[i].val;
412                         break;
413                 }
414 }
415
416 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
417 {
418         struct supplicant_interface *interface = user_data;
419         const char *str = NULL;
420         int i;
421
422         dbus_message_iter_get_basic(iter, &str);
423         if (str == NULL)
424                 return;
425
426         for (i = 0; mode_capa_map[i].str != NULL; i++)
427                 if (strcmp(str, mode_capa_map[i].str) == 0) {
428                         interface->mode_capa |= mode_capa_map[i].val;
429                         break;
430                 }
431 }
432
433 static void interface_capability(const char *key, DBusMessageIter *iter,
434                                                         void *user_data)
435 {
436         struct supplicant_interface *interface = user_data;
437
438         if (key == NULL)
439                 return;
440
441         if (g_strcmp0(key, "KeyMgmt") == 0)
442                 supplicant_dbus_array_foreach(iter,
443                                 interface_capability_keymgmt, interface);
444         else if (g_strcmp0(key, "AuthAlg") == 0)
445                 supplicant_dbus_array_foreach(iter,
446                                 interface_capability_authalg, interface);
447         else if (g_strcmp0(key, "Protocol") == 0)
448                 supplicant_dbus_array_foreach(iter, interface_capability_proto,
449                                                                 interface);
450         else if (g_strcmp0(key, "Scan") == 0)
451                 supplicant_dbus_array_foreach(iter, interface_capability_scan,
452                                                                 interface);
453         else if (g_strcmp0(key, "Modes") == 0)
454                 supplicant_dbus_array_foreach(iter, interface_capability_mode,
455                                                                 interface);
456         else
457                 DBG("key %s type %c",
458                                 key, dbus_message_iter_get_arg_type(iter));
459 }
460
461 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
462 {
463         if (interface == NULL)
464                 return NULL;
465
466         return interface->ifname;
467 }
468
469 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
470 {
471         if (network == NULL)
472                 return NULL;
473
474         return network->interface;
475 }
476
477 const char *supplicant_network_get_name(struct supplicant_network *network)
478 {
479         if (network == NULL || network->name == NULL)
480                 return "";
481
482         return network->name;
483 }
484
485 const char *supplicant_network_get_identifier(struct supplicant_network *network)
486 {
487         if (network == NULL || network->group == NULL)
488                 return "";
489
490         return network->group;
491 }
492
493 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
494 {
495         if (network == NULL)
496                 return SUPPLICANT_MODE_UNKNOWN;
497
498         return network->mode;
499 }
500
501 static void network_property(const char *key, DBusMessageIter *iter,
502                                                         void *user_data)
503 {
504         if (key == NULL)
505                 return;
506
507         DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
508 }
509
510 static void interface_network_added(DBusMessageIter *iter, void *user_data)
511 {
512         const char *path = NULL;
513
514         dbus_message_iter_get_basic(iter, &path);
515         if (path == NULL)
516                 return;
517
518         if (g_strcmp0(path, "/") == 0)
519                 return;
520
521         DBG("path %s", path);
522
523         supplicant_dbus_property_get_all(path,
524                                 SUPPLICANT_INTERFACE ".Interface.Network",
525                                                 network_property, NULL);
526 }
527
528 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
529 {
530         const char *path = NULL;
531
532         dbus_message_iter_get_basic(iter, &path);
533         if (path == NULL)
534                 return;
535
536         DBG("path %s", path);
537 }
538
539 static char *create_name(unsigned char *ssid, int ssid_len)
540 {
541         char *name;
542         int i;
543
544         if (ssid_len < 1 || ssid[0] == '\0')
545                 name = NULL;
546         else
547                 name = g_try_malloc0(ssid_len + 1);
548
549         if (name == NULL)
550                 return g_strdup("");
551
552         for (i = 0; i < ssid_len; i++) {
553                 if (g_ascii_isprint(ssid[i]))
554                         name[i] = ssid[i];
555                 else
556                         name[i] = ' ';
557         }
558
559         return name;
560 }
561
562 static char *create_group(struct supplicant_bss *bss)
563 {
564         GString *str;
565         unsigned int i;
566         const char *mode, *security;
567
568         str = g_string_sized_new((bss->ssid_len * 2) + 24);
569         if (str == NULL)
570                 return NULL;
571
572         if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
573                 for (i = 0; i < bss->ssid_len; i++)
574                         g_string_append_printf(str, "%02x", bss->ssid[i]);
575         } else
576                 g_string_append_printf(str, "hidden");
577
578         mode = mode2string(bss->mode);
579         if (mode != NULL)
580                 g_string_append_printf(str, "_%s", mode);
581
582         security = security2string(bss->security);
583         if (security != NULL)
584                 g_string_append_printf(str, "_%s", security);
585
586         return g_string_free(str, FALSE);
587 }
588
589 static void add_bss_to_network(struct supplicant_bss *bss)
590 {
591         struct supplicant_interface *interface = bss->interface;
592         struct supplicant_network *network;
593         char *group;
594
595         group = create_group(bss);
596         if (group == NULL)
597                 return;
598
599         network = g_hash_table_lookup(interface->network_table, group);
600         if (network != NULL) {
601                 g_free(group);
602                 goto done;
603         }
604
605         network = g_try_new0(struct supplicant_network, 1);
606         if (network == NULL) {
607                 g_free(group);
608                 return;
609         }
610
611         network->group = group;
612         network->name = create_name(bss->ssid, bss->ssid_len);
613         network->mode = bss->mode;
614
615         network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
616                                                         NULL, remove_bss);
617
618         g_hash_table_replace(interface->network_table,
619                                                 network->group, network);
620
621         callback_network_added(network);
622
623 done:
624         g_hash_table_replace(interface->bss_mapping, bss->path, network);
625         g_hash_table_replace(network->bss_table, bss->path, bss);
626 }
627
628 static unsigned char wifi_oui[3]      = { 0x00, 0x50, 0xf2 };
629 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
630
631 static void extract_rsn(struct supplicant_bss *bss,
632                                         const unsigned char *buf, int len)
633 {
634         uint16_t count;
635         int i;
636
637         /* Version */
638         if (len < 2)
639                 return;
640
641         buf += 2;
642         len -= 2;
643
644         /* Group cipher */
645         if (len < 4)
646                 return;
647
648         buf += 4;
649         len -= 4;
650
651         /* Pairwise cipher */
652         if (len < 2)
653                 return;
654
655         count = buf[0] | (buf[1] << 8);
656         if (2 + (count * 4) > len)
657                 return;
658
659         buf += 2 + (count * 4);
660         len -= 2 + (count * 4);
661
662         /* Authentication */
663         if (len < 2)
664                 return;
665
666         count = buf[0] | (buf[1] << 8);
667         if (2 + (count * 4) > len)
668                 return;
669
670         for (i = 0; i < count; i++) {
671                 const unsigned char *ptr = buf + 2 + (i * 4);
672
673                 if (memcmp(ptr, wifi_oui, 3) == 0) {
674                         switch (ptr[3]) {
675                         case 1:
676                                 bss->ieee8021x = TRUE;
677                                 break;
678                         case 2:
679                                 bss->psk = TRUE;
680                                 break;
681                         }
682                 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
683                         switch (ptr[3]) {
684                         case 1:
685                                 bss->ieee8021x = TRUE;
686                                 break;
687                         case 2:
688                                 bss->psk = TRUE;
689                                 break;
690                         }
691                 }
692         }
693
694         buf += 2 + (count * 4);
695         len -= 2 + (count * 4);
696 }
697
698 static void bss_property(const char *key, DBusMessageIter *iter,
699                                                         void *user_data)
700 {
701         struct supplicant_bss *bss = user_data;
702
703         if (bss->interface == NULL)
704                 return;
705
706         if (key == NULL) {
707                 if (bss->ieee8021x == TRUE)
708                         bss->security = SUPPLICANT_SECURITY_IEEE8021X;
709                 else if (bss->psk == TRUE)
710                         bss->security = SUPPLICANT_SECURITY_PSK;
711                 else if (bss->privacy == TRUE)
712                         bss->security = SUPPLICANT_SECURITY_WEP;
713                 else
714                         bss->security = SUPPLICANT_SECURITY_NONE;
715
716                 add_bss_to_network(bss);
717                 return;
718         }
719
720         if (g_strcmp0(key, "BSSID") == 0) {
721                 DBusMessageIter array;
722                 unsigned char *addr;
723                 int addr_len;
724
725                 dbus_message_iter_recurse(iter, &array);
726                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
727
728                 if (addr_len == 6)
729                         memcpy(bss->bssid, addr, addr_len);
730         } else if (g_strcmp0(key, "SSID") == 0) {
731                 DBusMessageIter array;
732                 unsigned char *ssid;
733                 int ssid_len;
734
735                 dbus_message_iter_recurse(iter, &array);
736                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
737
738                 if (ssid_len > 0 && ssid_len < 33) {
739                         memcpy(bss->ssid, ssid, ssid_len);
740                         bss->ssid_len = ssid_len;
741                 } else {
742                         memset(bss->ssid, 0, sizeof(bss->ssid));
743                         bss->ssid_len = 0;
744                 }
745         } else if (g_strcmp0(key, "Capabilities") == 0) {
746                 dbus_uint16_t capabilities = 0x0000;
747
748                 dbus_message_iter_get_basic(iter, &capabilities);
749
750                 if (capabilities & IEEE80211_CAP_ESS)
751                         bss->mode = SUPPLICANT_MODE_INFRA;
752                 else if (capabilities & IEEE80211_CAP_IBSS)
753                         bss->mode = SUPPLICANT_MODE_IBSS;
754
755                 if (capabilities & IEEE80211_CAP_PRIVACY)
756                         bss->privacy = TRUE;
757         } else if (g_strcmp0(key, "Mode") == 0) {
758                 const char *mode = NULL;
759
760                 dbus_message_iter_get_basic(iter, &mode);
761                 bss->mode = string2mode(mode);
762         } else if (g_strcmp0(key, "Frequency") == 0) {
763                 dbus_uint16_t frequency = 0;
764
765                 dbus_message_iter_get_basic(iter, &frequency);
766                 bss->frequency = frequency;
767         } else if (g_strcmp0(key, "Signal") == 0) {
768                 dbus_int16_t signal = 0;
769
770                 dbus_message_iter_get_basic(iter, &signal);
771         } else if (g_strcmp0(key, "Level") == 0) {
772                 dbus_int32_t level = 0;
773
774                 dbus_message_iter_get_basic(iter, &level);
775         } else if (g_strcmp0(key, "MaxRate") == 0) {
776                 dbus_uint16_t maxrate = 0;
777
778                 dbus_message_iter_get_basic(iter, &maxrate);
779         } else if (g_strcmp0(key, "Privacy") == 0) {
780                 dbus_bool_t privacy = FALSE;
781
782                 dbus_message_iter_get_basic(iter, &privacy);
783                 bss->privacy = privacy;
784         } else if (g_strcmp0(key, "RSNIE") == 0) {
785                 DBusMessageIter array;
786                 unsigned char *ie;
787                 int ie_len;
788
789                 dbus_message_iter_recurse(iter, &array);
790                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
791
792                 if (ie_len > 2)
793                         extract_rsn(bss, ie + 2, ie_len - 2);
794         } else if (g_strcmp0(key, "WPAIE") == 0) {
795                 DBusMessageIter array;
796                 unsigned char *ie;
797                 int ie_len;
798
799                 dbus_message_iter_recurse(iter, &array);
800                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
801
802                 if (ie_len > 6)
803                         extract_rsn(bss, ie + 6, ie_len - 6);
804         } else if (g_strcmp0(key, "WPSIE") == 0) {
805                 DBusMessageIter array;
806                 unsigned char *ie;
807                 int ie_len;
808
809                 dbus_message_iter_recurse(iter, &array);
810                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
811         } else
812                 DBG("key %s type %c",
813                                 key, dbus_message_iter_get_arg_type(iter));
814 }
815
816 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
817 {
818         struct supplicant_interface *interface = user_data;
819         struct supplicant_network *network;
820         struct supplicant_bss *bss;
821         const char *path = NULL;
822
823         dbus_message_iter_get_basic(iter, &path);
824         if (path == NULL)
825                 return;
826
827         if (g_strcmp0(path, "/") == 0)
828                 return;
829
830         network = g_hash_table_lookup(interface->bss_mapping, path);
831         if (network != NULL) {
832                 bss = g_hash_table_lookup(network->bss_table, path);
833                 if (bss != NULL)
834                         return;
835         }
836
837         bss = g_try_new0(struct supplicant_bss, 1);
838         if (bss == NULL)
839                 return;
840
841         bss->interface = interface;
842         bss->path = g_strdup(path);
843
844         supplicant_dbus_property_get_all(path,
845                                         SUPPLICANT_INTERFACE ".Interface.BSS",
846                                                         bss_property, bss);
847 }
848
849 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
850 {
851         struct supplicant_interface *interface = user_data;
852         struct supplicant_network *network;
853         const char *path = NULL;
854
855         dbus_message_iter_get_basic(iter, &path);
856         if (path == NULL)
857                 return;
858
859         network = g_hash_table_lookup(interface->bss_mapping, path);
860         if (network == NULL)
861                 return;
862
863         g_hash_table_remove(interface->bss_mapping, path);
864         g_hash_table_remove(network->bss_table, path);
865
866         if (g_hash_table_size(network->bss_table) == 0)
867                 g_hash_table_remove(interface->network_table, network->group);
868 }
869
870 static void interface_property(const char *key, DBusMessageIter *iter,
871                                                         void *user_data)
872 {
873         struct supplicant_interface *interface = user_data;
874
875         if (interface == NULL)
876                 return;
877
878         if (key == NULL) {
879                 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
880                                                 interface->keymgmt_capa);
881                 debug_strvalmap("AuthAlg capability", authalg_capa_map,
882                                                 interface->authalg_capa);
883                 debug_strvalmap("Protocol capability", proto_capa_map,
884                                                         interface->proto_capa);
885                 debug_strvalmap("Scan capability", scan_capa_map,
886                                                         interface->scan_capa);
887                 debug_strvalmap("Mode capability", mode_capa_map,
888                                                         interface->mode_capa);
889
890                 callback_interface_added(interface);
891                 return;
892         }
893
894         if (g_strcmp0(key, "Capabilities") == 0) {
895                 supplicant_dbus_property_foreach(iter, interface_capability,
896                                                                 interface);
897         } else if (g_strcmp0(key, "State") == 0) {
898                 const char *str = NULL;
899
900                 dbus_message_iter_get_basic(iter, &str);
901                 if (str != NULL)
902                         interface->state = string2state(str);
903         } else if (g_strcmp0(key, "Scanning") == 0) {
904                 dbus_bool_t scanning = FALSE;
905
906                 dbus_message_iter_get_basic(iter, &scanning);
907                 interface->scanning = scanning;
908         } else if (g_strcmp0(key, "ApScan") == 0) {
909                 int apscan;
910
911                 dbus_message_iter_get_basic(iter, &apscan);
912                 interface->apscan = apscan;
913         } else if (g_strcmp0(key, "Ifname") == 0) {
914                 const char *str = NULL;
915
916                 dbus_message_iter_get_basic(iter, &str);
917                 if (str != NULL)
918                         interface->ifname = g_strdup(str);
919         } else if (g_strcmp0(key, "Driver") == 0) {
920                 const char *str = NULL;
921
922                 dbus_message_iter_get_basic(iter, &str);
923                 if (str != NULL)
924                         interface->driver = g_strdup(str);
925         } else if (g_strcmp0(key, "BridgeIfname") == 0) {
926                 const char *str = NULL;
927
928                 dbus_message_iter_get_basic(iter, &str);
929                 if (str != NULL)
930                         interface->bridge = g_strdup(str);
931         } else if (g_strcmp0(key, "CurrentBSS") == 0) {
932                 interface_bss_added(iter, interface);
933         } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
934                 interface_network_added(iter, interface);
935         } else if (g_strcmp0(key, "BSSs") == 0) {
936                 supplicant_dbus_array_foreach(iter, interface_bss_added,
937                                                                 interface);
938         } else if (g_strcmp0(key, "Blobs") == 0) {
939         } else if (g_strcmp0(key, "Networks") == 0) {
940                 supplicant_dbus_array_foreach(iter, interface_network_added,
941                                                                 interface);
942         } else
943                 DBG("key %s type %c",
944                                 key, dbus_message_iter_get_arg_type(iter));
945 }
946
947 static struct supplicant_interface *interface_alloc(const char *path)
948 {
949         struct supplicant_interface *interface;
950
951         interface = g_try_new0(struct supplicant_interface, 1);
952         if (interface == NULL)
953                 return NULL;
954
955         interface->path = g_strdup(path);
956
957         interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
958                                                         NULL, remove_network);
959
960         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
961                                                                 NULL, NULL);
962
963         g_hash_table_replace(interface_table, interface->path, interface);
964
965         return interface;
966 }
967
968 static void interface_added(DBusMessageIter *iter, void *user_data)
969 {
970         struct supplicant_interface *interface;
971         const char *path = NULL;
972
973         dbus_message_iter_get_basic(iter, &path);
974         if (path == NULL)
975                 return;
976
977         if (g_strcmp0(path, "/") == 0)
978                 return;
979
980         interface = g_hash_table_lookup(interface_table, path);
981         if (interface != NULL)
982                 return;
983
984         interface = interface_alloc(path);
985         if (interface == NULL)
986                 return;
987
988         supplicant_dbus_property_get_all(path,
989                                         SUPPLICANT_INTERFACE ".Interface",
990                                                 interface_property, interface);
991 }
992
993 static void interface_removed(DBusMessageIter *iter, void *user_data)
994 {
995         const char *path = NULL;
996
997         dbus_message_iter_get_basic(iter, &path);
998         if (path == NULL)
999                 return;
1000
1001         g_hash_table_remove(interface_table, path);
1002 }
1003
1004 static void eap_method(DBusMessageIter *iter, void *user_data)
1005 {
1006         const char *str = NULL;
1007         int i;
1008
1009         dbus_message_iter_get_basic(iter, &str);
1010         if (str == NULL)
1011                 return;
1012
1013         for (i = 0; eap_method_map[i].str != NULL; i++)
1014                 if (strcmp(str, eap_method_map[i].str) == 0) {
1015                         eap_methods |= eap_method_map[i].val;
1016                         break;
1017                 }
1018 }
1019
1020 static void service_property(const char *key, DBusMessageIter *iter,
1021                                                         void *user_data)
1022 {
1023         if (key == NULL) {
1024                 callback_system_ready();
1025                 return;
1026         }
1027
1028         if (g_strcmp0(key, "DebugParams") == 0) {
1029                 DBusMessageIter list;
1030
1031                 dbus_message_iter_recurse(iter, &list);
1032                 dbus_message_iter_get_basic(&list, &debug_level);
1033
1034                 dbus_message_iter_next(&list);
1035                 dbus_message_iter_get_basic(&list, &debug_timestamp);
1036
1037                 dbus_message_iter_next(&list);
1038                 dbus_message_iter_get_basic(&list, &debug_showkeys);
1039
1040                 DBG("Debug level %d (timestamp %u show keys %u)",
1041                                 debug_level, debug_timestamp, debug_showkeys);
1042         } else if (g_strcmp0(key, "DebugLevel") == 0) {
1043                 dbus_message_iter_get_basic(iter, &debug_level);
1044                 DBG("Debug level %d", debug_level);
1045         } else if (g_strcmp0(key, "DebugTimeStamp") == 0) {
1046                 dbus_message_iter_get_basic(iter, &debug_timestamp);
1047                 DBG("Debug timestamp %u", debug_timestamp);
1048         } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1049                 dbus_message_iter_get_basic(iter, &debug_showkeys);
1050                 DBG("Debug show keys %u", debug_showkeys);
1051         } else if (g_strcmp0(key, "Interfaces") == 0) {
1052                 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1053         } else if (g_strcmp0(key, "EapMethods") == 0) {
1054                 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1055                 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1056         } else
1057                 DBG("key %s type %c",
1058                                 key, dbus_message_iter_get_arg_type(iter));
1059 }
1060
1061 static void supplicant_bootstrap(void)
1062 {
1063         supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1064                                                 SUPPLICANT_INTERFACE,
1065                                                 service_property, NULL);
1066 }
1067
1068 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1069 {
1070         const char *name = NULL, *old = NULL, *new = NULL;
1071
1072         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1073                 return;
1074
1075         dbus_message_iter_get_basic(iter, &name);
1076         if (name == NULL)
1077                 return;
1078
1079         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1080                 return;
1081
1082         dbus_message_iter_next(iter);
1083         dbus_message_iter_get_basic(iter, &old);
1084         dbus_message_iter_next(iter);
1085         dbus_message_iter_get_basic(iter, &new);
1086
1087         if (old == NULL || new == NULL)
1088                 return;
1089
1090         if (strlen(old) > 0 && strlen(new) == 0) {
1091                 system_available = FALSE;
1092                 g_hash_table_remove_all(interface_table);
1093                 callback_system_killed();
1094         }
1095
1096         if (strlen(new) > 0 && strlen(old) == 0) {
1097                 system_available = TRUE;
1098                 supplicant_bootstrap();
1099         }
1100 }
1101
1102 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1103 {
1104         if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1105                 return;
1106
1107         supplicant_dbus_property_foreach(iter, service_property, NULL);
1108 }
1109
1110 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1111 {
1112         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1113                 interface_added(iter, NULL);
1114 }
1115
1116 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1117 {
1118         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1119                 interface_removed(iter, NULL);
1120 }
1121
1122 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1123 {
1124         struct supplicant_interface *interface;
1125
1126         interface = g_hash_table_lookup(interface_table, path);
1127         if (interface == NULL)
1128                 return;
1129
1130         interface_bss_added(iter, interface);
1131 }
1132
1133 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1134 {
1135         struct supplicant_interface *interface;
1136
1137         interface = g_hash_table_lookup(interface_table, path);
1138         if (interface == NULL)
1139                 return;
1140
1141         interface_bss_removed(iter, interface);
1142 }
1143
1144 static void signal_network_added(const char *path, DBusMessageIter *iter)
1145 {
1146         struct supplicant_interface *interface;
1147
1148         interface = g_hash_table_lookup(interface_table, path);
1149         if (interface == NULL)
1150                 return;
1151
1152         interface_network_added(iter, interface);
1153 }
1154
1155 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1156 {
1157         struct supplicant_interface *interface;
1158
1159         interface = g_hash_table_lookup(interface_table, path);
1160         if (interface == NULL)
1161                 return;
1162
1163         interface_network_removed(iter, interface);
1164 }
1165
1166 static struct {
1167         const char *interface;
1168         const char *member;
1169         void (*function) (const char *path, DBusMessageIter *iter);
1170 } signal_map[] = {
1171         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
1172
1173         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1174         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
1175         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
1176         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
1177
1178         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",       signal_bss_added       },
1179         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",     signal_bss_removed     },
1180         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",   signal_network_added   },
1181         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1182
1183         { }
1184 };
1185
1186 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1187                                         DBusMessage *message, void *data)
1188 {
1189         DBusMessageIter iter;
1190         const char *path;
1191         int i;
1192
1193         path = dbus_message_get_path(message);
1194         if (path == NULL)
1195                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1196
1197         if (dbus_message_iter_init(message, &iter) == FALSE)
1198                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1199
1200         for (i = 0; signal_map[i].interface != NULL; i++) {
1201                 if (dbus_message_has_interface(message,
1202                                         signal_map[i].interface) == FALSE)
1203                         continue;
1204
1205                 if (dbus_message_has_member(message,
1206                                         signal_map[i].member) == FALSE)
1207                         continue;
1208
1209                 signal_map[i].function(path, &iter);
1210                 break;
1211         }
1212
1213         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1214 }
1215
1216 static const char *supplicant_rule0 = "type=signal,"
1217                                         "path=" DBUS_PATH_DBUS ","
1218                                         "sender=" DBUS_SERVICE_DBUS ","
1219                                         "interface=" DBUS_INTERFACE_DBUS ","
1220                                         "member=NameOwnerChanged,"
1221                                         "arg0=" SUPPLICANT_SERVICE;
1222 static const char *supplicant_rule1 = "type=signal,"
1223                         "interface=" SUPPLICANT_INTERFACE;
1224 static const char *supplicant_rule2 = "type=signal,"
1225                         "interface=" SUPPLICANT_INTERFACE ".Interface";
1226 static const char *supplicant_rule3 = "type=signal,"
1227                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1228 static const char *supplicant_rule4 = "type=signal,"
1229                         "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1230 static const char *supplicant_rule5 = "type=signal,"
1231                         "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1232 static const char *supplicant_rule6 = "type=signal,"
1233                         "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1234
1235 int supplicant_register(const struct supplicant_callbacks *callbacks)
1236 {
1237         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1238         if (connection == NULL)
1239                 return -EIO;
1240
1241         if (dbus_connection_add_filter(connection,
1242                                 supplicant_filter, NULL, NULL) == FALSE) {
1243                 dbus_connection_unref(connection);
1244                 connection = NULL;
1245                 return -EIO;
1246         }
1247
1248         callbacks_pointer = callbacks;
1249         eap_methods = 0;
1250
1251         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1252                                                 NULL, remove_interface);
1253
1254         supplicant_dbus_setup(connection);
1255
1256         dbus_bus_add_match(connection, supplicant_rule0, NULL);
1257         dbus_bus_add_match(connection, supplicant_rule1, NULL);
1258         dbus_bus_add_match(connection, supplicant_rule2, NULL);
1259         dbus_bus_add_match(connection, supplicant_rule3, NULL);
1260         dbus_bus_add_match(connection, supplicant_rule4, NULL);
1261         dbus_bus_add_match(connection, supplicant_rule5, NULL);
1262         dbus_bus_add_match(connection, supplicant_rule6, NULL);
1263         dbus_connection_flush(connection);
1264
1265         if (dbus_bus_name_has_owner(connection,
1266                                         SUPPLICANT_SERVICE, NULL) == TRUE) {
1267                 system_available = TRUE;
1268                 supplicant_bootstrap();
1269         }
1270
1271         return 0;
1272 }
1273
1274 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1275 {
1276         if (connection != NULL) {
1277                 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1278                 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1279                 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1280                 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1281                 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1282                 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1283                 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1284                 dbus_connection_flush(connection);
1285
1286                 dbus_connection_remove_filter(connection,
1287                                                 supplicant_filter, NULL);
1288         }
1289
1290         if (interface_table != NULL) {
1291                 g_hash_table_destroy(interface_table);
1292                 interface_table = NULL;
1293         }
1294
1295         if (system_available == TRUE)
1296                 callback_system_killed();
1297
1298         if (connection != NULL) {
1299                 dbus_connection_unref(connection);
1300                 connection = NULL;
1301         }
1302
1303         callbacks_pointer = NULL;
1304         eap_methods = 0;
1305 }
1306
1307 static void debug_level_result(const char *error,
1308                                 DBusMessageIter *iter, void *user_data)
1309 {
1310         if (error != NULL)
1311                 DBG("debug level failure: %s", error);
1312 }
1313
1314 static void add_debug_level(DBusMessageIter *iter, void *user_data)
1315 {
1316         dbus_int32_t level = GPOINTER_TO_UINT(user_data);
1317         DBusMessageIter entry;
1318
1319         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1320                                                         NULL, &entry);
1321
1322         dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
1323         dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1324                                                 &debug_timestamp);
1325         dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1326                                                 &debug_showkeys);
1327
1328         dbus_message_iter_close_container(iter, &entry);
1329 }
1330
1331 void supplicant_set_debug_level(unsigned int level)
1332 {
1333         if (system_available == FALSE)
1334                 return;
1335
1336         supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1337                                 "DebugParams", "(ibb)", add_debug_level,
1338                                 debug_level_result, GUINT_TO_POINTER(level));
1339 }
1340
1341 struct interface_create_data {
1342         const char *ifname;
1343         const char *driver;
1344         struct supplicant_interface *interface;
1345         supplicant_interface_create_callback callback;
1346         void *user_data;
1347 };
1348
1349 static void interface_create_property(const char *key, DBusMessageIter *iter,
1350                                                         void *user_data)
1351 {
1352         struct interface_create_data *data = user_data;
1353         struct supplicant_interface *interface = data->interface;
1354
1355         if (key == NULL) {
1356                 if (data->callback != NULL)
1357                         data->callback(0, data->interface, data->user_data);
1358
1359                 dbus_free(data);
1360         }
1361
1362         interface_property(key, iter, interface);
1363 }
1364
1365 static void interface_create_result(const char *error,
1366                                 DBusMessageIter *iter, void *user_data)
1367 {
1368         struct interface_create_data *data = user_data;
1369         const char *path = NULL;
1370         int err;
1371
1372         if (error != NULL) {
1373                 err = -EIO;
1374                 goto done;
1375         }
1376
1377         dbus_message_iter_get_basic(iter, &path);
1378         if (path == NULL) {
1379                 err = -EINVAL;
1380                 goto done;
1381         }
1382
1383         if (system_available == FALSE) {
1384                 err = -EFAULT;
1385                 goto done;
1386         }
1387
1388         data->interface = g_hash_table_lookup(interface_table, path);
1389         if (data->interface == NULL) {
1390                 data->interface = interface_alloc(path);
1391                 if (data->interface == NULL) {
1392                         err = -ENOMEM;
1393                         goto done;
1394                 }
1395         }
1396
1397         err = supplicant_dbus_property_get_all(path,
1398                                         SUPPLICANT_INTERFACE ".Interface",
1399                                         interface_create_property, data);
1400         if (err == 0)
1401                 return;
1402
1403 done:
1404         if (data->callback != NULL)
1405                 data->callback(err, NULL, data->user_data);
1406
1407         dbus_free(data);
1408 }
1409
1410 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1411 {
1412         struct interface_create_data *data = user_data;
1413         DBusMessageIter dict;
1414
1415         supplicant_dbus_dict_open(iter, &dict);
1416
1417         supplicant_dbus_dict_append_basic(&dict, "Ifname",
1418                                         DBUS_TYPE_STRING, &data->ifname);
1419         supplicant_dbus_dict_append_basic(&dict, "Driver",
1420                                         DBUS_TYPE_STRING, &data->driver);
1421
1422         supplicant_dbus_dict_close(iter, &dict);
1423 }
1424
1425 static void interface_get_result(const char *error,
1426                                 DBusMessageIter *iter, void *user_data)
1427 {
1428         struct interface_create_data *data = user_data;
1429         struct supplicant_interface *interface;
1430         const char *path = NULL;
1431         int err;
1432
1433         if (error != NULL) {
1434                 err = -EIO;
1435                 goto create;
1436         }
1437
1438         dbus_message_iter_get_basic(iter, &path);
1439         if (path == NULL) {
1440                 err = -EINVAL;
1441                 goto done;
1442         }
1443
1444         interface = g_hash_table_lookup(interface_table, path);
1445         if (interface == NULL) {
1446                 err = -ENOENT;
1447                 goto done;
1448         }
1449
1450         if (data->callback != NULL)
1451                 data->callback(0, interface, data->user_data);
1452
1453         dbus_free(data);
1454
1455         return;
1456
1457 create:
1458         if (system_available == FALSE) {
1459                 err = -EFAULT;
1460                 goto done;
1461         }
1462
1463         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1464                                                 SUPPLICANT_INTERFACE,
1465                                                 "CreateInterface",
1466                                                 interface_create_params,
1467                                                 interface_create_result, data);
1468         if (err == 0)
1469                 return;
1470
1471 done:
1472         if (data->callback != NULL)
1473                 data->callback(err, NULL, data->user_data);
1474
1475         dbus_free(data);
1476 }
1477
1478 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1479 {
1480         struct interface_create_data *data = user_data;
1481
1482         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1483 }
1484
1485 int supplicant_interface_create(const char *ifname, const char *driver,
1486                         supplicant_interface_create_callback callback,
1487                                                         void *user_data)
1488 {
1489         struct interface_create_data *data;
1490
1491         if (system_available == FALSE)
1492                 return -EFAULT;
1493
1494         data = dbus_malloc0(sizeof(*data));
1495         if (data == NULL)
1496                 return -ENOMEM;
1497
1498         data->ifname = ifname;
1499         data->driver = driver;
1500         data->callback = callback;
1501         data->user_data = user_data;
1502
1503         return supplicant_dbus_method_call(SUPPLICANT_PATH,
1504                                                 SUPPLICANT_INTERFACE,
1505                                                 "GetInterface",
1506                                                 interface_get_params,
1507                                                 interface_get_result, data);
1508 }
1509
1510 int supplicant_interface_remove(struct supplicant_interface *interface,
1511                         supplicant_interface_remove_callback callback,
1512                                                         void *user_data)
1513 {
1514         if (system_available == FALSE)
1515                 return -EFAULT;
1516
1517         return 0;
1518 }