Add support for supplicant signals with included properties
[platform/upstream/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         //struct supplicant_interface *interface = user_data;
513         const char *path = NULL;
514
515         dbus_message_iter_get_basic(iter, &path);
516         if (path == NULL)
517                 return;
518
519         if (g_strcmp0(path, "/") == 0)
520                 return;
521
522         dbus_message_iter_next(iter);
523         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
524                 supplicant_dbus_property_foreach(iter, network_property, NULL);
525                 network_property(NULL, NULL, NULL);
526                 return;
527         }
528
529         supplicant_dbus_property_get_all(path,
530                                 SUPPLICANT_INTERFACE ".Interface.Network",
531                                                 network_property, NULL);
532 }
533
534 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
535 {
536         const char *path = NULL;
537
538         dbus_message_iter_get_basic(iter, &path);
539         if (path == NULL)
540                 return;
541
542         DBG("path %s", path);
543 }
544
545 static char *create_name(unsigned char *ssid, int ssid_len)
546 {
547         char *name;
548         int i;
549
550         if (ssid_len < 1 || ssid[0] == '\0')
551                 name = NULL;
552         else
553                 name = g_try_malloc0(ssid_len + 1);
554
555         if (name == NULL)
556                 return g_strdup("");
557
558         for (i = 0; i < ssid_len; i++) {
559                 if (g_ascii_isprint(ssid[i]))
560                         name[i] = ssid[i];
561                 else
562                         name[i] = ' ';
563         }
564
565         return name;
566 }
567
568 static char *create_group(struct supplicant_bss *bss)
569 {
570         GString *str;
571         unsigned int i;
572         const char *mode, *security;
573
574         str = g_string_sized_new((bss->ssid_len * 2) + 24);
575         if (str == NULL)
576                 return NULL;
577
578         if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
579                 for (i = 0; i < bss->ssid_len; i++)
580                         g_string_append_printf(str, "%02x", bss->ssid[i]);
581         } else
582                 g_string_append_printf(str, "hidden");
583
584         mode = mode2string(bss->mode);
585         if (mode != NULL)
586                 g_string_append_printf(str, "_%s", mode);
587
588         security = security2string(bss->security);
589         if (security != NULL)
590                 g_string_append_printf(str, "_%s", security);
591
592         return g_string_free(str, FALSE);
593 }
594
595 static void add_bss_to_network(struct supplicant_bss *bss)
596 {
597         struct supplicant_interface *interface = bss->interface;
598         struct supplicant_network *network;
599         char *group;
600
601         group = create_group(bss);
602         if (group == NULL)
603                 return;
604
605         network = g_hash_table_lookup(interface->network_table, group);
606         if (network != NULL) {
607                 g_free(group);
608                 goto done;
609         }
610
611         network = g_try_new0(struct supplicant_network, 1);
612         if (network == NULL) {
613                 g_free(group);
614                 return;
615         }
616
617         network->group = group;
618         network->name = create_name(bss->ssid, bss->ssid_len);
619         network->mode = bss->mode;
620
621         network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
622                                                         NULL, remove_bss);
623
624         g_hash_table_replace(interface->network_table,
625                                                 network->group, network);
626
627         callback_network_added(network);
628
629 done:
630         g_hash_table_replace(interface->bss_mapping, bss->path, network);
631         g_hash_table_replace(network->bss_table, bss->path, bss);
632 }
633
634 static unsigned char wifi_oui[3]      = { 0x00, 0x50, 0xf2 };
635 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
636
637 static void extract_rsn(struct supplicant_bss *bss,
638                                         const unsigned char *buf, int len)
639 {
640         uint16_t count;
641         int i;
642
643         /* Version */
644         if (len < 2)
645                 return;
646
647         buf += 2;
648         len -= 2;
649
650         /* Group cipher */
651         if (len < 4)
652                 return;
653
654         buf += 4;
655         len -= 4;
656
657         /* Pairwise cipher */
658         if (len < 2)
659                 return;
660
661         count = buf[0] | (buf[1] << 8);
662         if (2 + (count * 4) > len)
663                 return;
664
665         buf += 2 + (count * 4);
666         len -= 2 + (count * 4);
667
668         /* Authentication */
669         if (len < 2)
670                 return;
671
672         count = buf[0] | (buf[1] << 8);
673         if (2 + (count * 4) > len)
674                 return;
675
676         for (i = 0; i < count; i++) {
677                 const unsigned char *ptr = buf + 2 + (i * 4);
678
679                 if (memcmp(ptr, wifi_oui, 3) == 0) {
680                         switch (ptr[3]) {
681                         case 1:
682                                 bss->ieee8021x = TRUE;
683                                 break;
684                         case 2:
685                                 bss->psk = TRUE;
686                                 break;
687                         }
688                 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
689                         switch (ptr[3]) {
690                         case 1:
691                                 bss->ieee8021x = TRUE;
692                                 break;
693                         case 2:
694                                 bss->psk = TRUE;
695                                 break;
696                         }
697                 }
698         }
699
700         buf += 2 + (count * 4);
701         len -= 2 + (count * 4);
702 }
703
704 static void bss_property(const char *key, DBusMessageIter *iter,
705                                                         void *user_data)
706 {
707         struct supplicant_bss *bss = user_data;
708
709         if (bss->interface == NULL)
710                 return;
711
712         if (key == NULL) {
713                 if (bss->ieee8021x == TRUE)
714                         bss->security = SUPPLICANT_SECURITY_IEEE8021X;
715                 else if (bss->psk == TRUE)
716                         bss->security = SUPPLICANT_SECURITY_PSK;
717                 else if (bss->privacy == TRUE)
718                         bss->security = SUPPLICANT_SECURITY_WEP;
719                 else
720                         bss->security = SUPPLICANT_SECURITY_NONE;
721
722                 add_bss_to_network(bss);
723                 return;
724         }
725
726         if (g_strcmp0(key, "BSSID") == 0) {
727                 DBusMessageIter array;
728                 unsigned char *addr;
729                 int addr_len;
730
731                 dbus_message_iter_recurse(iter, &array);
732                 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
733
734                 if (addr_len == 6)
735                         memcpy(bss->bssid, addr, addr_len);
736         } else if (g_strcmp0(key, "SSID") == 0) {
737                 DBusMessageIter array;
738                 unsigned char *ssid;
739                 int ssid_len;
740
741                 dbus_message_iter_recurse(iter, &array);
742                 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
743
744                 if (ssid_len > 0 && ssid_len < 33) {
745                         memcpy(bss->ssid, ssid, ssid_len);
746                         bss->ssid_len = ssid_len;
747                 } else {
748                         memset(bss->ssid, 0, sizeof(bss->ssid));
749                         bss->ssid_len = 0;
750                 }
751         } else if (g_strcmp0(key, "Capabilities") == 0) {
752                 dbus_uint16_t capabilities = 0x0000;
753
754                 dbus_message_iter_get_basic(iter, &capabilities);
755
756                 if (capabilities & IEEE80211_CAP_ESS)
757                         bss->mode = SUPPLICANT_MODE_INFRA;
758                 else if (capabilities & IEEE80211_CAP_IBSS)
759                         bss->mode = SUPPLICANT_MODE_IBSS;
760
761                 if (capabilities & IEEE80211_CAP_PRIVACY)
762                         bss->privacy = TRUE;
763         } else if (g_strcmp0(key, "Mode") == 0) {
764                 const char *mode = NULL;
765
766                 dbus_message_iter_get_basic(iter, &mode);
767                 bss->mode = string2mode(mode);
768         } else if (g_strcmp0(key, "Frequency") == 0) {
769                 dbus_uint16_t frequency = 0;
770
771                 dbus_message_iter_get_basic(iter, &frequency);
772                 bss->frequency = frequency;
773         } else if (g_strcmp0(key, "Signal") == 0) {
774                 dbus_int16_t signal = 0;
775
776                 dbus_message_iter_get_basic(iter, &signal);
777         } else if (g_strcmp0(key, "Level") == 0) {
778                 dbus_int32_t level = 0;
779
780                 dbus_message_iter_get_basic(iter, &level);
781         } else if (g_strcmp0(key, "MaxRate") == 0) {
782                 dbus_uint16_t maxrate = 0;
783
784                 dbus_message_iter_get_basic(iter, &maxrate);
785         } else if (g_strcmp0(key, "Privacy") == 0) {
786                 dbus_bool_t privacy = FALSE;
787
788                 dbus_message_iter_get_basic(iter, &privacy);
789                 bss->privacy = privacy;
790         } else if (g_strcmp0(key, "RSNIE") == 0) {
791                 DBusMessageIter array;
792                 unsigned char *ie;
793                 int ie_len;
794
795                 dbus_message_iter_recurse(iter, &array);
796                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
797
798                 if (ie_len > 2)
799                         extract_rsn(bss, ie + 2, ie_len - 2);
800         } else if (g_strcmp0(key, "WPAIE") == 0) {
801                 DBusMessageIter array;
802                 unsigned char *ie;
803                 int ie_len;
804
805                 dbus_message_iter_recurse(iter, &array);
806                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
807
808                 if (ie_len > 6)
809                         extract_rsn(bss, ie + 6, ie_len - 6);
810         } else if (g_strcmp0(key, "WPSIE") == 0) {
811                 DBusMessageIter array;
812                 unsigned char *ie;
813                 int ie_len;
814
815                 dbus_message_iter_recurse(iter, &array);
816                 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
817         } else
818                 DBG("key %s type %c",
819                                 key, dbus_message_iter_get_arg_type(iter));
820 }
821
822 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
823 {
824         struct supplicant_interface *interface = user_data;
825         struct supplicant_network *network;
826         struct supplicant_bss *bss;
827         const char *path = NULL;
828
829         dbus_message_iter_get_basic(iter, &path);
830         if (path == NULL)
831                 return;
832
833         if (g_strcmp0(path, "/") == 0)
834                 return;
835
836         network = g_hash_table_lookup(interface->bss_mapping, path);
837         if (network != NULL) {
838                 bss = g_hash_table_lookup(network->bss_table, path);
839                 if (bss != NULL)
840                         return;
841         }
842
843         bss = g_try_new0(struct supplicant_bss, 1);
844         if (bss == NULL)
845                 return;
846
847         bss->interface = interface;
848         bss->path = g_strdup(path);
849
850         dbus_message_iter_next(iter);
851         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
852                 supplicant_dbus_property_foreach(iter, bss_property, bss);
853                 bss_property(NULL, NULL, bss);
854                 return;
855         }
856
857         supplicant_dbus_property_get_all(path,
858                                         SUPPLICANT_INTERFACE ".Interface.BSS",
859                                                         bss_property, bss);
860 }
861
862 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
863 {
864         struct supplicant_interface *interface = user_data;
865         struct supplicant_network *network;
866         const char *path = NULL;
867
868         dbus_message_iter_get_basic(iter, &path);
869         if (path == NULL)
870                 return;
871
872         network = g_hash_table_lookup(interface->bss_mapping, path);
873         if (network == NULL)
874                 return;
875
876         g_hash_table_remove(interface->bss_mapping, path);
877         g_hash_table_remove(network->bss_table, path);
878
879         if (g_hash_table_size(network->bss_table) == 0)
880                 g_hash_table_remove(interface->network_table, network->group);
881 }
882
883 static void interface_property(const char *key, DBusMessageIter *iter,
884                                                         void *user_data)
885 {
886         struct supplicant_interface *interface = user_data;
887
888         if (interface == NULL)
889                 return;
890
891         if (key == NULL) {
892                 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
893                                                 interface->keymgmt_capa);
894                 debug_strvalmap("AuthAlg capability", authalg_capa_map,
895                                                 interface->authalg_capa);
896                 debug_strvalmap("Protocol capability", proto_capa_map,
897                                                         interface->proto_capa);
898                 debug_strvalmap("Scan capability", scan_capa_map,
899                                                         interface->scan_capa);
900                 debug_strvalmap("Mode capability", mode_capa_map,
901                                                         interface->mode_capa);
902
903                 callback_interface_added(interface);
904                 return;
905         }
906
907         if (g_strcmp0(key, "Capabilities") == 0) {
908                 supplicant_dbus_property_foreach(iter, interface_capability,
909                                                                 interface);
910         } else if (g_strcmp0(key, "State") == 0) {
911                 const char *str = NULL;
912
913                 dbus_message_iter_get_basic(iter, &str);
914                 if (str != NULL)
915                         interface->state = string2state(str);
916         } else if (g_strcmp0(key, "Scanning") == 0) {
917                 dbus_bool_t scanning = FALSE;
918
919                 dbus_message_iter_get_basic(iter, &scanning);
920                 interface->scanning = scanning;
921         } else if (g_strcmp0(key, "ApScan") == 0) {
922                 int apscan;
923
924                 dbus_message_iter_get_basic(iter, &apscan);
925                 interface->apscan = apscan;
926         } else if (g_strcmp0(key, "Ifname") == 0) {
927                 const char *str = NULL;
928
929                 dbus_message_iter_get_basic(iter, &str);
930                 if (str != NULL)
931                         interface->ifname = g_strdup(str);
932         } else if (g_strcmp0(key, "Driver") == 0) {
933                 const char *str = NULL;
934
935                 dbus_message_iter_get_basic(iter, &str);
936                 if (str != NULL)
937                         interface->driver = g_strdup(str);
938         } else if (g_strcmp0(key, "BridgeIfname") == 0) {
939                 const char *str = NULL;
940
941                 dbus_message_iter_get_basic(iter, &str);
942                 if (str != NULL)
943                         interface->bridge = g_strdup(str);
944         } else if (g_strcmp0(key, "CurrentBSS") == 0) {
945                 interface_bss_added(iter, interface);
946         } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
947                 interface_network_added(iter, interface);
948         } else if (g_strcmp0(key, "BSSs") == 0) {
949                 supplicant_dbus_array_foreach(iter, interface_bss_added,
950                                                                 interface);
951         } else if (g_strcmp0(key, "Blobs") == 0) {
952         } else if (g_strcmp0(key, "Networks") == 0) {
953                 supplicant_dbus_array_foreach(iter, interface_network_added,
954                                                                 interface);
955         } else
956                 DBG("key %s type %c",
957                                 key, dbus_message_iter_get_arg_type(iter));
958 }
959
960 static struct supplicant_interface *interface_alloc(const char *path)
961 {
962         struct supplicant_interface *interface;
963
964         interface = g_try_new0(struct supplicant_interface, 1);
965         if (interface == NULL)
966                 return NULL;
967
968         interface->path = g_strdup(path);
969
970         interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
971                                                         NULL, remove_network);
972
973         interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
974                                                                 NULL, NULL);
975
976         g_hash_table_replace(interface_table, interface->path, interface);
977
978         return interface;
979 }
980
981 static void interface_added(DBusMessageIter *iter, void *user_data)
982 {
983         struct supplicant_interface *interface;
984         const char *path = NULL;
985
986         dbus_message_iter_get_basic(iter, &path);
987         if (path == NULL)
988                 return;
989
990         if (g_strcmp0(path, "/") == 0)
991                 return;
992
993         interface = g_hash_table_lookup(interface_table, path);
994         if (interface != NULL)
995                 return;
996
997         interface = interface_alloc(path);
998         if (interface == NULL)
999                 return;
1000
1001         dbus_message_iter_next(iter);
1002         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1003                 supplicant_dbus_property_foreach(iter, interface_property,
1004                                                                 interface);
1005                 interface_property(NULL, NULL, interface);
1006                 return;
1007         }
1008
1009         supplicant_dbus_property_get_all(path,
1010                                         SUPPLICANT_INTERFACE ".Interface",
1011                                                 interface_property, interface);
1012 }
1013
1014 static void interface_removed(DBusMessageIter *iter, void *user_data)
1015 {
1016         const char *path = NULL;
1017
1018         dbus_message_iter_get_basic(iter, &path);
1019         if (path == NULL)
1020                 return;
1021
1022         g_hash_table_remove(interface_table, path);
1023 }
1024
1025 static void eap_method(DBusMessageIter *iter, void *user_data)
1026 {
1027         const char *str = NULL;
1028         int i;
1029
1030         dbus_message_iter_get_basic(iter, &str);
1031         if (str == NULL)
1032                 return;
1033
1034         for (i = 0; eap_method_map[i].str != NULL; i++)
1035                 if (strcmp(str, eap_method_map[i].str) == 0) {
1036                         eap_methods |= eap_method_map[i].val;
1037                         break;
1038                 }
1039 }
1040
1041 static void service_property(const char *key, DBusMessageIter *iter,
1042                                                         void *user_data)
1043 {
1044         if (key == NULL) {
1045                 callback_system_ready();
1046                 return;
1047         }
1048
1049         if (g_strcmp0(key, "DebugParams") == 0) {
1050                 DBusMessageIter list;
1051
1052                 dbus_message_iter_recurse(iter, &list);
1053                 dbus_message_iter_get_basic(&list, &debug_level);
1054
1055                 dbus_message_iter_next(&list);
1056                 dbus_message_iter_get_basic(&list, &debug_timestamp);
1057
1058                 dbus_message_iter_next(&list);
1059                 dbus_message_iter_get_basic(&list, &debug_showkeys);
1060
1061                 DBG("Debug level %d (timestamp %u show keys %u)",
1062                                 debug_level, debug_timestamp, debug_showkeys);
1063         } else if (g_strcmp0(key, "DebugLevel") == 0) {
1064                 dbus_message_iter_get_basic(iter, &debug_level);
1065                 DBG("Debug level %d", debug_level);
1066         } else if (g_strcmp0(key, "DebugTimeStamp") == 0) {
1067                 dbus_message_iter_get_basic(iter, &debug_timestamp);
1068                 DBG("Debug timestamp %u", debug_timestamp);
1069         } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1070                 dbus_message_iter_get_basic(iter, &debug_showkeys);
1071                 DBG("Debug show keys %u", debug_showkeys);
1072         } else if (g_strcmp0(key, "Interfaces") == 0) {
1073                 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1074         } else if (g_strcmp0(key, "EapMethods") == 0) {
1075                 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1076                 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1077         } else
1078                 DBG("key %s type %c",
1079                                 key, dbus_message_iter_get_arg_type(iter));
1080 }
1081
1082 static void supplicant_bootstrap(void)
1083 {
1084         supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1085                                                 SUPPLICANT_INTERFACE,
1086                                                 service_property, NULL);
1087 }
1088
1089 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1090 {
1091         const char *name = NULL, *old = NULL, *new = NULL;
1092
1093         if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1094                 return;
1095
1096         dbus_message_iter_get_basic(iter, &name);
1097         if (name == NULL)
1098                 return;
1099
1100         if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1101                 return;
1102
1103         dbus_message_iter_next(iter);
1104         dbus_message_iter_get_basic(iter, &old);
1105         dbus_message_iter_next(iter);
1106         dbus_message_iter_get_basic(iter, &new);
1107
1108         if (old == NULL || new == NULL)
1109                 return;
1110
1111         if (strlen(old) > 0 && strlen(new) == 0) {
1112                 system_available = FALSE;
1113                 g_hash_table_remove_all(interface_table);
1114                 callback_system_killed();
1115         }
1116
1117         if (strlen(new) > 0 && strlen(old) == 0) {
1118                 system_available = TRUE;
1119                 supplicant_bootstrap();
1120         }
1121 }
1122
1123 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1124 {
1125         if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1126                 return;
1127
1128         supplicant_dbus_property_foreach(iter, service_property, NULL);
1129 }
1130
1131 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1132 {
1133         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1134                 interface_added(iter, NULL);
1135 }
1136
1137 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1138 {
1139         if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1140                 interface_removed(iter, NULL);
1141 }
1142
1143 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1144 {
1145         struct supplicant_interface *interface;
1146
1147         interface = g_hash_table_lookup(interface_table, path);
1148         if (interface == NULL)
1149                 return;
1150
1151         interface_bss_added(iter, interface);
1152 }
1153
1154 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1155 {
1156         struct supplicant_interface *interface;
1157
1158         interface = g_hash_table_lookup(interface_table, path);
1159         if (interface == NULL)
1160                 return;
1161
1162         interface_bss_removed(iter, interface);
1163 }
1164
1165 static void signal_network_added(const char *path, DBusMessageIter *iter)
1166 {
1167         struct supplicant_interface *interface;
1168
1169         interface = g_hash_table_lookup(interface_table, path);
1170         if (interface == NULL)
1171                 return;
1172
1173         interface_network_added(iter, interface);
1174 }
1175
1176 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1177 {
1178         struct supplicant_interface *interface;
1179
1180         interface = g_hash_table_lookup(interface_table, path);
1181         if (interface == NULL)
1182                 return;
1183
1184         interface_network_removed(iter, interface);
1185 }
1186
1187 static struct {
1188         const char *interface;
1189         const char *member;
1190         void (*function) (const char *path, DBusMessageIter *iter);
1191 } signal_map[] = {
1192         { DBUS_INTERFACE_DBUS,  "NameOwnerChanged",  signal_name_owner_changed },
1193
1194         { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1195         { SUPPLICANT_INTERFACE, "InterfaceAdded",    signal_interface_added    },
1196         { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
1197         { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
1198
1199         { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",       signal_bss_added       },
1200         { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",     signal_bss_removed     },
1201         { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",   signal_network_added   },
1202         { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1203
1204         { }
1205 };
1206
1207 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1208                                         DBusMessage *message, void *data)
1209 {
1210         DBusMessageIter iter;
1211         const char *path;
1212         int i;
1213
1214         path = dbus_message_get_path(message);
1215         if (path == NULL)
1216                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1217
1218         if (dbus_message_iter_init(message, &iter) == FALSE)
1219                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1220
1221         for (i = 0; signal_map[i].interface != NULL; i++) {
1222                 if (dbus_message_has_interface(message,
1223                                         signal_map[i].interface) == FALSE)
1224                         continue;
1225
1226                 if (dbus_message_has_member(message,
1227                                         signal_map[i].member) == FALSE)
1228                         continue;
1229
1230                 signal_map[i].function(path, &iter);
1231                 break;
1232         }
1233
1234         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1235 }
1236
1237 static const char *supplicant_rule0 = "type=signal,"
1238                                         "path=" DBUS_PATH_DBUS ","
1239                                         "sender=" DBUS_SERVICE_DBUS ","
1240                                         "interface=" DBUS_INTERFACE_DBUS ","
1241                                         "member=NameOwnerChanged,"
1242                                         "arg0=" SUPPLICANT_SERVICE;
1243 static const char *supplicant_rule1 = "type=signal,"
1244                         "interface=" SUPPLICANT_INTERFACE;
1245 static const char *supplicant_rule2 = "type=signal,"
1246                         "interface=" SUPPLICANT_INTERFACE ".Interface";
1247 static const char *supplicant_rule3 = "type=signal,"
1248                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1249 static const char *supplicant_rule4 = "type=signal,"
1250                         "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1251 static const char *supplicant_rule5 = "type=signal,"
1252                         "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1253 static const char *supplicant_rule6 = "type=signal,"
1254                         "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1255
1256 int supplicant_register(const struct supplicant_callbacks *callbacks)
1257 {
1258         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1259         if (connection == NULL)
1260                 return -EIO;
1261
1262         if (dbus_connection_add_filter(connection,
1263                                 supplicant_filter, NULL, NULL) == FALSE) {
1264                 dbus_connection_unref(connection);
1265                 connection = NULL;
1266                 return -EIO;
1267         }
1268
1269         callbacks_pointer = callbacks;
1270         eap_methods = 0;
1271
1272         interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1273                                                 NULL, remove_interface);
1274
1275         supplicant_dbus_setup(connection);
1276
1277         dbus_bus_add_match(connection, supplicant_rule0, NULL);
1278         dbus_bus_add_match(connection, supplicant_rule1, NULL);
1279         dbus_bus_add_match(connection, supplicant_rule2, NULL);
1280         dbus_bus_add_match(connection, supplicant_rule3, NULL);
1281         dbus_bus_add_match(connection, supplicant_rule4, NULL);
1282         dbus_bus_add_match(connection, supplicant_rule5, NULL);
1283         dbus_bus_add_match(connection, supplicant_rule6, NULL);
1284         dbus_connection_flush(connection);
1285
1286         if (dbus_bus_name_has_owner(connection,
1287                                         SUPPLICANT_SERVICE, NULL) == TRUE) {
1288                 system_available = TRUE;
1289                 supplicant_bootstrap();
1290         }
1291
1292         return 0;
1293 }
1294
1295 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1296 {
1297         if (connection != NULL) {
1298                 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1299                 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1300                 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1301                 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1302                 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1303                 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1304                 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1305                 dbus_connection_flush(connection);
1306
1307                 dbus_connection_remove_filter(connection,
1308                                                 supplicant_filter, NULL);
1309         }
1310
1311         if (interface_table != NULL) {
1312                 g_hash_table_destroy(interface_table);
1313                 interface_table = NULL;
1314         }
1315
1316         if (system_available == TRUE)
1317                 callback_system_killed();
1318
1319         if (connection != NULL) {
1320                 dbus_connection_unref(connection);
1321                 connection = NULL;
1322         }
1323
1324         callbacks_pointer = NULL;
1325         eap_methods = 0;
1326 }
1327
1328 static void debug_level_result(const char *error,
1329                                 DBusMessageIter *iter, void *user_data)
1330 {
1331         if (error != NULL)
1332                 DBG("debug level failure: %s", error);
1333 }
1334
1335 static void add_debug_level(DBusMessageIter *iter, void *user_data)
1336 {
1337         dbus_int32_t level = GPOINTER_TO_UINT(user_data);
1338         DBusMessageIter entry;
1339
1340         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1341                                                         NULL, &entry);
1342
1343         dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
1344         dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1345                                                 &debug_timestamp);
1346         dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1347                                                 &debug_showkeys);
1348
1349         dbus_message_iter_close_container(iter, &entry);
1350 }
1351
1352 void supplicant_set_debug_level(unsigned int level)
1353 {
1354         if (system_available == FALSE)
1355                 return;
1356
1357         supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1358                                 "DebugParams", "(ibb)", add_debug_level,
1359                                 debug_level_result, GUINT_TO_POINTER(level));
1360 }
1361
1362 struct interface_create_data {
1363         const char *ifname;
1364         const char *driver;
1365         struct supplicant_interface *interface;
1366         supplicant_interface_create_callback callback;
1367         void *user_data;
1368 };
1369
1370 static void interface_create_property(const char *key, DBusMessageIter *iter,
1371                                                         void *user_data)
1372 {
1373         struct interface_create_data *data = user_data;
1374         struct supplicant_interface *interface = data->interface;
1375
1376         if (key == NULL) {
1377                 if (data->callback != NULL)
1378                         data->callback(0, data->interface, data->user_data);
1379
1380                 dbus_free(data);
1381         }
1382
1383         interface_property(key, iter, interface);
1384 }
1385
1386 static void interface_create_result(const char *error,
1387                                 DBusMessageIter *iter, void *user_data)
1388 {
1389         struct interface_create_data *data = user_data;
1390         const char *path = NULL;
1391         int err;
1392
1393         if (error != NULL) {
1394                 err = -EIO;
1395                 goto done;
1396         }
1397
1398         dbus_message_iter_get_basic(iter, &path);
1399         if (path == NULL) {
1400                 err = -EINVAL;
1401                 goto done;
1402         }
1403
1404         if (system_available == FALSE) {
1405                 err = -EFAULT;
1406                 goto done;
1407         }
1408
1409         data->interface = g_hash_table_lookup(interface_table, path);
1410         if (data->interface == NULL) {
1411                 data->interface = interface_alloc(path);
1412                 if (data->interface == NULL) {
1413                         err = -ENOMEM;
1414                         goto done;
1415                 }
1416         }
1417
1418         err = supplicant_dbus_property_get_all(path,
1419                                         SUPPLICANT_INTERFACE ".Interface",
1420                                         interface_create_property, data);
1421         if (err == 0)
1422                 return;
1423
1424 done:
1425         if (data->callback != NULL)
1426                 data->callback(err, NULL, data->user_data);
1427
1428         dbus_free(data);
1429 }
1430
1431 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1432 {
1433         struct interface_create_data *data = user_data;
1434         DBusMessageIter dict;
1435
1436         supplicant_dbus_dict_open(iter, &dict);
1437
1438         supplicant_dbus_dict_append_basic(&dict, "Ifname",
1439                                         DBUS_TYPE_STRING, &data->ifname);
1440         supplicant_dbus_dict_append_basic(&dict, "Driver",
1441                                         DBUS_TYPE_STRING, &data->driver);
1442
1443         supplicant_dbus_dict_close(iter, &dict);
1444 }
1445
1446 static void interface_get_result(const char *error,
1447                                 DBusMessageIter *iter, void *user_data)
1448 {
1449         struct interface_create_data *data = user_data;
1450         struct supplicant_interface *interface;
1451         const char *path = NULL;
1452         int err;
1453
1454         if (error != NULL) {
1455                 err = -EIO;
1456                 goto create;
1457         }
1458
1459         dbus_message_iter_get_basic(iter, &path);
1460         if (path == NULL) {
1461                 err = -EINVAL;
1462                 goto done;
1463         }
1464
1465         interface = g_hash_table_lookup(interface_table, path);
1466         if (interface == NULL) {
1467                 err = -ENOENT;
1468                 goto done;
1469         }
1470
1471         if (data->callback != NULL)
1472                 data->callback(0, interface, data->user_data);
1473
1474         dbus_free(data);
1475
1476         return;
1477
1478 create:
1479         if (system_available == FALSE) {
1480                 err = -EFAULT;
1481                 goto done;
1482         }
1483
1484         err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1485                                                 SUPPLICANT_INTERFACE,
1486                                                 "CreateInterface",
1487                                                 interface_create_params,
1488                                                 interface_create_result, data);
1489         if (err == 0)
1490                 return;
1491
1492 done:
1493         if (data->callback != NULL)
1494                 data->callback(err, NULL, data->user_data);
1495
1496         dbus_free(data);
1497 }
1498
1499 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1500 {
1501         struct interface_create_data *data = user_data;
1502
1503         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1504 }
1505
1506 int supplicant_interface_create(const char *ifname, const char *driver,
1507                         supplicant_interface_create_callback callback,
1508                                                         void *user_data)
1509 {
1510         struct interface_create_data *data;
1511
1512         if (system_available == FALSE)
1513                 return -EFAULT;
1514
1515         data = dbus_malloc0(sizeof(*data));
1516         if (data == NULL)
1517                 return -ENOMEM;
1518
1519         data->ifname = ifname;
1520         data->driver = driver;
1521         data->callback = callback;
1522         data->user_data = user_data;
1523
1524         return supplicant_dbus_method_call(SUPPLICANT_PATH,
1525                                                 SUPPLICANT_INTERFACE,
1526                                                 "GetInterface",
1527                                                 interface_get_params,
1528                                                 interface_get_result, data);
1529 }
1530
1531 int supplicant_interface_remove(struct supplicant_interface *interface,
1532                         supplicant_interface_remove_callback callback,
1533                                                         void *user_data)
1534 {
1535         if (system_available == FALSE)
1536                 return -EFAULT;
1537
1538         return 0;
1539 }